# 导入基础模块
import copy

import numpy as np
import pandas as pd

import matplotlib as mpl 
import matplotlib.pyplot as plt

import openseespy.opensees as ops

from datetime import datetime
import json




# 单元长度计算
def element_len_cal(node_1_tag, node_2_tag):
    x_1 = ops.nodeCoord(node_1_tag)[0]
    y_1 = ops.nodeCoord(node_1_tag)[1]
    z_1 = ops.nodeCoord(node_1_tag)[2]
    
    x_2 = ops.nodeCoord(node_2_tag)[0]
    y_2 = ops.nodeCoord(node_2_tag)[1]
    z_2 = ops.nodeCoord(node_2_tag)[2]
    
    ele_len = np.sqrt((x_1 - x_2) **2 + (y_1 - y_2) ** 2 + (z_1 - z_2) ** 2)
    
    return ele_len





# 单元重力荷载施加
def element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                             node_1_tag, node_2_tag):
    
    ele_G = 9.8 * ele_len * \
            sec_info_dict[sec_tag][0][0] * sec_info_dict[sec_tag][1][0]
    
    ops.load(node_1_tag, *[0.0, 0.0, -ele_G/2, 0.0, 0.0, 0.0])
    ops.load(node_2_tag, *[0.0, 0.0, -ele_G/2, 0.0, 0.0, 0.0])




# 修正转动惯量（针对加劲梁）
def moment_of_inertia_correct(location_index, temp_moment_inertia_list, ele_len, \
                                sec_info_dict, sec_tag, \
                                node_num, node_1_tag, node_2_tag, \
                                skeleton):
    # 校正加劲梁转动惯量
    # 获取转动惯量差值
    if location_index == 0:
        temp_moment_inertia_list[0] = (sec_info_dict[sec_tag][1][1] + sec_info_dict[sec_tag][1][2] - \
                                        sec_info_dict[sec_tag][1][3]) * sec_info_dict[sec_tag][0][0] * \
                                        ele_len / 3
        temp_moment_inertia_list[1] = (sec_info_dict[sec_tag][1][1] + sec_info_dict[sec_tag][1][2] - \
                                        sec_info_dict[sec_tag][1][3]) * sec_info_dict[sec_tag][0][0] * \
                                        ele_len / 3
    else:
        temp_moment_inertia_list[0] = temp_moment_inertia_list[1]
        temp_moment_inertia_list[0] += (sec_info_dict[sec_tag][1][1] + sec_info_dict[sec_tag][1][2] - \
                                        sec_info_dict[sec_tag][1][3]) * sec_info_dict[sec_tag][0][0] * \
                                            ele_len / 3
        temp_moment_inertia_list[1] = (sec_info_dict[sec_tag][1][1] + sec_info_dict[sec_tag][1][2] - \
                                        sec_info_dict[sec_tag][1][3]) * sec_info_dict[sec_tag][0][0] * \
                                        ele_len / 3
#         if location_index == 200:
#             print(sec_info_dict[sec_tag][1][1], sec_info_dict[sec_tag][1][2], sec_info_dict[sec_tag][1][3], \
#                  sec_info_dict[sec_tag][0][0], ele_len)
    
    # 通过增加集中转动惯量
    if location_index == (node_num-2):
        ops.mass(node_1_tag, *[0.0, 0.0, 0.0, 0.0, temp_moment_inertia_list[0], 0.0])
        ops.mass(node_2_tag, *[0.0, 0.0, 0.0, 0.0, temp_moment_inertia_list[1], 0.0])

        skeleton['nodes'][node_1_tag]['mass'] = [0.0, 0.0, 0.0, 0.0, temp_moment_inertia_list[0], 0.0]
        skeleton['nodes'][node_2_tag]['mass'] = [0.0, 0.0, 0.0, 0.0, temp_moment_inertia_list[1], 0.0]

    else:
        ops.mass(node_1_tag, *[0.0, 0.0, 0.0, 0.0, temp_moment_inertia_list[0], 0.0])

        skeleton['nodes'][node_1_tag]['mass'] = [0.0, 0.0, 0.0, 0.0, temp_moment_inertia_list[0], 0.0]
        



# 加劲梁建模
def stiffening_girder_modelling(main_span_len, main_span_num, side_span_len_1, side_span_len_2, \
                                    cable_num, girder_z, girder_width, \
                                    girder_sec_para_1, girder_mat_para_1, \
                                    girder_sec_para_2, girder_mat_para_2, \
                                    skeleton, \
                                    gravity_index=0, load_pattern_tag=-1, time_series_tag=-1, \
                                    girder_sec_para_3_1=None, girder_mat_para_3_1=None, \
                                    girder_sec_para_3_2=None, girder_mat_para_3_2=None, \
                                    girder_3_ratio_1=None, girder_3_ratio_2=None, \
                                    no_anchor_len_side_1=-1, no_anchor_len_side_2=-1, \
                                    no_anchor_len_tower=-1, no_anchor_len_middle=-1, \
                                    insert_node_num=-1, densed_ratio_1=-1, densed_ratio_2=-1):
    
    # =========加劲梁有限元建模=========
    # 思路：按照均匀分布的原则求正常索间距大小，之后求拉索加密区的索间距大小
    # 无索区的纵向分段数量由其自身长度为正常索间距的倍数关系得到，其中主塔处的无索区纵向分段必须为偶数段
    # 现有分段结果的每一纵向节点都将建立一根虚拟横梁，此时再考虑辅助墩的放置位置，该位置根据已有的横梁位置进行选择
    # 这之后考虑对已有节点进行加密，加密策略为每两个节点间等间距插入节点
    # 梁体的纵曲线考虑为水平直线与圆曲线的组合，其中圆曲线半径取能刚好覆盖主跨跨径且边缘斜率为2%的半径大小，直线段取2%坡度
    # 加劲梁的绝对高度由程序输入值给出，该值表示y轴负半区最边缘主塔中心位置处加劲梁中心点的z坐标
    #
    # 数据格式：
    # main_span_len = 主跨跨径
    # main_span_num = 主跨数量
    # side_span_len_1 = 边跨（y轴负半区）跨径
    # side_span_len_2 = 边跨（y轴正半区）跨径
    # cable_num = 单侧拉索根数
    # girder_z = 加劲梁中心点在y轴负半区最边缘主塔中心位置处的z坐标值
    #
    # girder_width = 加劲梁宽度
    # girder_sec_para_1 = 加劲梁纵梁截面参数 = [截面积，Iz，Iy，Jxx]
    # girder_mat_para_1 = 加劲梁纵梁材料参数 = [材料密度，材料弹性模量，材料剪切模量]
    # girder_sec_para_2 = 加劲梁虚拟横梁截面参数 = [截面积，Iz，Iy，Jxx]
    # girder_mat_para_2 = 加劲梁虚拟横梁材料参数 = [材料密度，材料弹性模量，材料剪切模量]
    # 
    # skeleton = 桥梁骨架信息
    # 
    # gravity_index = 加劲梁建模是否同时进行重力荷载建模
    # load_pattern_tag = 荷载pattern编号
    # time_series_tag = 时间序列序号
    # 
    # girder_sec_para_3_1 = 加劲梁混合梁（或压重梁）纵梁边跨（y轴负半区）
    #                       混凝土（或压重）梁段截面参数 = [[截面积，Iz，Iy，Jxx], [截面积，Iz，Iy，Jxx], ...]
    # girder_mat_para_3_1 = 加劲梁混合梁（或压重梁）纵梁边跨（y轴负半区）
    #                       混凝土（或压重）梁段材料参数
    #                     = [[材料密度，材料弹性模量，材料剪切模量], [材料密度，材料弹性模量，材料剪切模量], ...]
    #
    # girder_sec_para_3_2 = 加劲梁混合梁（或压重梁）纵梁边跨（y轴正半区）
    #                       混凝土（或压重）梁段截面参数 = [[截面积，Iz，Iy，Jxx], [截面积，Iz，Iy，Jxx], ...]
    # girder_mat_para_3_2 = 加劲梁混合梁（或压重梁）纵梁边跨（y轴正半区）
    #                       混凝土（或压重）梁段材料参数 
    #                     = [[材料密度，材料弹性模量，材料剪切模量], [材料密度，材料弹性模量，材料剪切模量], ...]
    #
    # girder_3_ratio_1 = 加劲梁混合梁（或压重梁）纵梁边跨（y轴负半区）混凝土（或压重）梁段起止位置比例（与边跨长度作比）
    #                  = [[起点1， 终点1], [起点2， 终点2], ...]
    # girder_3_ratio_2 = 加劲梁混合梁（或压重梁）纵梁边跨（y轴正半区）混凝土（或压重）梁段起止位置比例（与边跨长度作比）
    #                  = [[起点1， 终点1], [起点2， 终点2], ...]
    # 
    # no_anchor_len_side_1 = 边跨（y轴负半区）边端无索区长度（以拉索加密区索间距倍数表示）
    # no_anchor_len_side_2 = 边跨（y轴正半区）边端无索区长度（以拉索加密区索间距倍数表示）
    # no_anchor_len_tower = 主塔底部无索区长度（以正常索间距倍数表示）
    # no_anchor_len_middle = 主跨跨中无索区长度（以正常索间距倍数表示）
    #
    # insert_node_num = 加密节点数
    # densed_ratio = 密索区长度占总索区长度的比值
    
    
    
    girder_G_list = []  # 加劲梁节段重量数组（主塔处一律考虑有竖向支撑）
    support_node_tag_list = []  # 支承节点序号数组

    # 计算加劲梁节点y坐标序列
    anchor_dis_normal = 0  # 正常索间距
    anchor_dis_densed_1 = 0 # 边跨（y轴负半区）加密索间距
    anchor_densed_num_1 = 0 # 边跨（y轴负半区）加密索间隔数
    anchor_dis_densed_2 = 0 # 边跨（y轴正半区）加密索间距
    anchor_densed_num_2 = 0 # 边跨（y轴正半区）加密索间隔数
    
    no_anchor_num_side_1 = 0  # 边跨（y轴负半区）边端无索区间隔数
    no_anchor_num_side_2 = 0  # 边跨（y轴正半区）边端无索区间隔数
    no_anchor_num_tower = 0  # 主塔无索区间隔数（单侧）
    no_anchor_num_middle = 0  # 主跨跨中无索区间隔数
    
    if insert_node_num == -1:
        insert_node_num = 0  # 插入加密节点数量
    
    # 程序允许用户自定义无索区间长度，在没有进行人为定义时，赋予默认值。
    if no_anchor_len_side_1 == -1:
        no_anchor_len_side_1 = 1
    
    no_anchor_num_side_1 = np.ceil(no_anchor_len_side_1)
    
    if no_anchor_len_side_2 == -1:
        no_anchor_len_side_2 = 1
    
    no_anchor_num_side_2 = np.ceil(no_anchor_len_side_2)
    
    if no_anchor_len_tower == -1:
        no_anchor_len_tower = 2
    no_anchor_num_tower = np.ceil(no_anchor_len_tower)
    if no_anchor_num_tower == 1:
        no_anchor_num_tower += 1  # 保证主塔下无索区至少有3根空置虚拟横梁
    
    if no_anchor_len_middle == -1:
        no_anchor_len_middle = 1
        
    no_anchor_num_middle = np.ceil(no_anchor_len_middle)
    if no_anchor_num_middle % 2 == 1:
        # 确保主跨跨中无索区划分段数为偶数段
        no_anchor_num_middle += 1
    
    
    # 非独塔斜拉桥
    if main_span_num > 0:

        # 正常索间距计算
        anchor_dis_normal = main_span_len / (2 * (cable_num - 1) + no_anchor_len_middle + no_anchor_len_tower * 2)
        
        # 边跨（y轴负半区）加密索间距计算
        side_span_len = side_span_len_1
        no_anchor_len_side = no_anchor_len_side_1
        anchor_dis_densed = 0
        anchor_densed_num = 0
        if ((side_span_len / main_span_len) < 0.3 and densed_ratio_1 == -1) or densed_ratio_1 >= 1000:
            # 当边中跨比小于0.3（待调整）且没有指定densed_ratio 或
            # densed_ratio为一个很大值（大于等于1000）时，考虑取全段有索区为加密段
            anchor_densed_num = cable_num - 1
            anchor_dis_densed = (side_span_len - anchor_dis_normal * no_anchor_len_tower) / \
                                    (anchor_densed_num + no_anchor_len_side)
        else:
            # 其他情况，考虑取全段有索区的densed_ratio为加密段
            # 通过试算计算出加密索区的分隔y坐标
            if densed_ratio_1 == -1:
                densed_ratio_1 = 0.25  # 密索区长度占总索区长度的比值
            densed_ele_num = np.floor(densed_ratio_1 * (cable_num - 1))  # 加密索区的单元数量
            while True:
                if densed_ele_num == 0:
                    # 不可能不存在密索区
                    densed_ele_num += 1
                else:
                    temp_densed_dis = (side_span_len - anchor_dis_normal * (cable_num - 1 - densed_ele_num + no_anchor_len_tower)) * \
                                        densed_ele_num / (densed_ele_num + no_anchor_len_side)
                    temp_normal_dis = anchor_dis_normal * (cable_num - 1 - densed_ele_num)
                    temp_ratio = temp_densed_dis / (temp_normal_dis + temp_densed_dis)  # 当前的加密索区与整个索区的长度比值
                    if temp_ratio < densed_ratio_1 or (temp_densed_dis / densed_ele_num) <= 1:
                        # 试算加密索区跨度比例不足densed_ratio或是试算得到的加密索间距小于等于1（可调整）时
                        densed_ele_num += 1
                    else:
                        anchor_densed_num = densed_ele_num
                        anchor_dis_densed = temp_densed_dis / densed_ele_num
                        break
                
        anchor_dis_densed_1 = anchor_dis_densed
        anchor_densed_num_1 = anchor_densed_num
        
        # 边跨（y轴正半区）加密索间距计算
        side_span_len = side_span_len_2
        no_anchor_len_side = no_anchor_len_side_2
        anchor_dis_densed = 0
        anchor_densed_num = 0
        if ((side_span_len / main_span_len) < 0.3 and densed_ratio_2 == -1) or densed_ratio_2 >= 1000:
            # 当边中跨比小于0.3（待调整）且没有指定densed_ratio 或
            # densed_ratio为一个很大值（大于等于1000）时，考虑取全段有索区为加密段
            anchor_densed_num = cable_num - 1
            anchor_dis_densed = (side_span_len - anchor_dis_normal * no_anchor_len_tower) / \
                                    (anchor_densed_num + no_anchor_len_side)
        else:
            # 其他情况，考虑取全段有索区的densed_ratio为加密段
            # 通过试算计算出加密索区的分隔y坐标
            if densed_ratio_2 == -1:
                densed_ratio_2 = 0.25  # 密索区长度占总索区长度的比值
            densed_ele_num = np.floor(densed_ratio_2 * (cable_num - 1))  # 加密索区的单元数量
            while True:
                if densed_ele_num == 0:
                    # 不可能不存在密索区
                    densed_ele_num += 1
                else:
                    temp_densed_dis = (side_span_len - anchor_dis_normal * (cable_num - 1 - densed_ele_num + no_anchor_len_tower)) * \
                                        densed_ele_num / (densed_ele_num + no_anchor_len_side)
                    temp_normal_dis = anchor_dis_normal * (cable_num - 1 - densed_ele_num)
                    temp_ratio = temp_densed_dis / (temp_normal_dis + temp_densed_dis)  # 当前的加密索区与整个索区的长度比值
                    if temp_ratio < densed_ratio_2 or (temp_densed_dis / densed_ele_num) <= 1:
                        # 试算加密索区跨度比例不足densed_ratio或是试算得到的加密索间距小于等于1（可调整）时
                        densed_ele_num += 1
                    else:
                        anchor_densed_num = densed_ele_num
                        anchor_dis_densed = temp_densed_dis / densed_ele_num
                        break
                
        anchor_dis_densed_2 = anchor_dis_densed
        anchor_densed_num_2 = anchor_densed_num

    # 独塔斜拉桥（暂时按照均匀布置去处理）
    else:
        # 当没有完整提供两跨的拉索加密比例时，默认拉索等间距布置
        if densed_ratio_1 == -1 or densed_ratio_1 >= 1000 or \
            densed_ratio_2 == -1 or densed_ratio_2 >= 1000:
            
            # 边跨（y轴负半区）加密索间距计算
            side_span_len = side_span_len_1
            no_anchor_len_side = no_anchor_len_side_1
                    
            anchor_dis_densed_1 = side_span_len / (no_anchor_len_side + (cable_num - 1) + no_anchor_len_tower)
            anchor_densed_num_1 = cable_num - 1
            
            # 边跨（y轴正半区）加密索间距计算
            side_span_len = side_span_len_2
            no_anchor_len_side = no_anchor_len_side_2
                    
            anchor_dis_densed_2 = side_span_len / (no_anchor_len_side + (cable_num - 1) + no_anchor_len_tower)
            anchor_densed_num_2 = cable_num - 1

            # 正常索间距计算
            anchor_dis_normal = anchor_dis_densed_2

        # 当完整提供两跨的拉索加密比例时，按实际间距布置
        else:
            
            # 边跨（y轴负半区）加密索间距计算
            side_span_len = side_span_len_1
            no_anchor_len_side = no_anchor_len_side_1
                    
            anchor_dis_densed_1 = side_span_len / (no_anchor_len_side + (cable_num - 1) + no_anchor_len_tower)
            anchor_densed_num_1 = cable_num - 1
            
            # 边跨（y轴正半区）加密索间距计算
            side_span_len = side_span_len_2
            no_anchor_len_side = no_anchor_len_side_2
                    
            anchor_dis_densed_2 = side_span_len / (no_anchor_len_side + (cable_num - 1) + no_anchor_len_tower)
            anchor_densed_num_2 = cable_num - 1

            # 正常索间距计算
            anchor_dis_normal = anchor_dis_densed_2
    
    
    
    # 获取y坐标序列
    y_shift = side_span_len_1 + main_span_len * main_span_num / 2  # y坐标起始偏移值大小
    y_list = []  # y坐标序列
    # 边跨（y轴负半区）y坐标序列
    y_start = 0 - y_shift
    y_end_1 = y_start + anchor_dis_densed_1 * no_anchor_len_side_1
    y_end_2 = y_end_1 + anchor_dis_densed_1 * anchor_densed_num_1
    y_end_3 = y_end_2 + anchor_dis_normal * (cable_num - 1 - anchor_densed_num_1)
    y_end_4 = side_span_len_1 - y_shift
    
    div_num_1 = int(no_anchor_num_side_1 * (insert_node_num + 1) + 1)
    div_num_2 = int(anchor_densed_num_1 * (insert_node_num + 1) + 1)
    div_num_3 = int((cable_num - 1 - anchor_densed_num_1) * (insert_node_num + 1) + 1)
    div_num_4 = int(no_anchor_num_tower * (insert_node_num + 1) + 1)
    
    y_array_1 = np.linspace(y_start, y_end_1, div_num_1)
    y_array_1 = np.round(y_array_1, 2)
    y_list_1 = list(y_array_1)
    y_list_1 = y_list_1[:-1]
    
    y_array_2 = np.linspace(y_end_1, y_end_2, div_num_2)
    y_array_2 = np.round(y_array_2, 2)
    y_list_2 = list(y_array_2)
    y_list_2 = y_list_2[:-1]
    
    y_array_3 = np.linspace(y_end_2, y_end_3, div_num_3)
    y_array_3 = np.round(y_array_3, 2)
    y_list_3 = list(y_array_3)
    y_list_3 = y_list_3[:-1]
    
    y_array_4 = np.linspace(y_end_3, y_end_4, div_num_4)
    y_array_4 = np.round(y_array_4, 2)
    y_list_4 = list(y_array_4)
    
    y_list_side_1 = y_list_1 + y_list_2 + y_list_3 + y_list_4  # 边跨（y轴正半区）y坐标序列定义
    y_list = y_list + y_list_side_1[:-1]

    support_node_tag_list_1 = [1]
    if y_start != y_end_1:
        support_node_tag_list_1 = list(np.linspace(1, div_num_1, 2).astype('int'))
    support_node_tag_list_2 = list(np.linspace(support_node_tag_list_1[-1], \
                                                support_node_tag_list_1[-1]+div_num_2-1+div_num_3-1, \
                                                    cable_num).astype('int'))
    support_node_tag_list_3 = list(np.linspace(support_node_tag_list_2[-1], \
                                                support_node_tag_list_2[-1]+div_num_4-1, 2).astype('int'))
    support_node_tag_list = support_node_tag_list_1[:-1] + support_node_tag_list_2[:-1] + \
                            support_node_tag_list_3
    
    # 主跨y坐标序列定义
    y_list_main = []  # 主跨y坐标序列数组（其中每个元素为单个主跨的y坐标序列）
    for i in range(main_span_num):
        y_start = side_span_len_1 + main_span_len * i - y_shift
        y_end_1 = y_start + no_anchor_len_tower * anchor_dis_normal
        y_end_2 = y_end_1 + (cable_num - 1) * anchor_dis_normal
        y_end_3 = y_end_2 + no_anchor_len_middle * anchor_dis_normal
        y_end_4 = y_end_3 + (cable_num - 1) * anchor_dis_normal
        y_end_5 = side_span_len_1 + main_span_len * (i + 1) - y_shift
        
        div_num_1 = int(no_anchor_num_tower * (insert_node_num + 1) + 1)
        div_num_2 = int((cable_num - 1) * (insert_node_num + 1) + 1)
        div_num_3 = int(no_anchor_num_middle * (insert_node_num + 1) + 1)
        div_num_4 = div_num_2
        div_num_5 = div_num_1

        y_array_1 = np.linspace(y_start, y_end_1, div_num_1)
        y_array_1 = np.round(y_array_1, 2)
        y_list_1 = list(y_array_1)
        y_list_1 = y_list_1[:-1]

        y_array_2 = np.linspace(y_end_1, y_end_2, div_num_2)
        y_array_2 = np.round(y_array_2, 2)
        y_list_2 = list(y_array_2)
        y_list_2 = y_list_2[:-1]

        y_array_3 = np.linspace(y_end_2, y_end_3, div_num_3)
        y_array_3 = np.round(y_array_3, 2)
        y_list_3 = list(y_array_3)
        y_list_3 = y_list_3[:-1]

        y_array_4 = np.linspace(y_end_3, y_end_4, div_num_4)
        y_array_4 = np.round(y_array_4, 2)
        y_list_4 = list(y_array_4)
        y_list_4 = y_list_4[:-1]

        y_array_5 = np.linspace(y_end_4, y_end_5, div_num_5)
        y_array_5 = np.round(y_array_5, 2)
        y_list_5 = list(y_array_5)

        y_list_main_1 = y_list_1 + y_list_2 + y_list_3 + y_list_4 + y_list_5  # 边跨（y轴正半区）y坐标序列定义
        y_list_main.append(y_list_main_1)
        y_list = y_list + y_list_main_1[:-1]

        support_node_tag_list_1 = list(np.linspace(support_node_tag_list[-1], \
                                                    support_node_tag_list[-1]+div_num_1-1, 2).astype('int'))
        support_node_tag_list_2 = list(np.linspace(support_node_tag_list_1[-1], \
                                                    support_node_tag_list_1[-1]+div_num_2-1, \
                                                        cable_num).astype('int'))
        support_node_tag_list_3 = list(np.linspace(support_node_tag_list_2[-1], \
                                                    support_node_tag_list_2[-1]+div_num_3-1, \
                                                        2).astype('int'))
        support_node_tag_list_4 = list(np.linspace(support_node_tag_list_3[-1], \
                                                    support_node_tag_list_3[-1]+div_num_4-1, \
                                                        cable_num).astype('int'))
        support_node_tag_list_5 = list(np.linspace(support_node_tag_list_4[-1], \
                                                    support_node_tag_list_4[-1]+div_num_5-1, \
                                                        2).astype('int'))
        support_node_tag_list = support_node_tag_list[:-1] + \
                                support_node_tag_list_1[:-1] + support_node_tag_list_2[:-1] + \
                                support_node_tag_list_3[:-1] + support_node_tag_list_4[:-1] + \
                                support_node_tag_list_5
    
    # 边跨（y轴正半区）y坐标序列
    y_start = side_span_len_1 + main_span_len * main_span_num - y_shift
    y_end_1 = y_start + anchor_dis_normal * no_anchor_len_tower
    y_end_2 = y_end_1 + anchor_dis_normal * (cable_num - 1 - anchor_densed_num_2)
    y_end_3 = y_end_2 + anchor_dis_densed_2 * anchor_densed_num_2
    y_end_4 = y_start + side_span_len_2
    
    div_num_1 = int(no_anchor_num_tower * (insert_node_num + 1) + 1)
    div_num_2 = int((cable_num - 1 - anchor_densed_num_2) * (insert_node_num + 1) + 1)
    div_num_3 = int(anchor_densed_num_2 * (insert_node_num + 1) + 1)
    div_num_4 = int(no_anchor_num_side_2 * (insert_node_num + 1) + 1)
    
    y_array_1 = np.linspace(y_start, y_end_1, div_num_1)
    y_array_1 = np.round(y_array_1, 2)
    y_list_1 = list(y_array_1)
    y_list_1 = y_list_1[:-1]
    
    y_array_2 = np.linspace(y_end_1, y_end_2, div_num_2)
    y_array_2 = np.round(y_array_2, 2)
    y_list_2 = list(y_array_2)
    y_list_2 = y_list_2[:-1]
    
    y_array_3 = np.linspace(y_end_2, y_end_3, div_num_3)
    y_array_3 = np.round(y_array_3, 2)
    y_list_3 = list(y_array_3)
    y_list_3 = y_list_3[:-1]
    
    y_array_4 = np.linspace(y_end_3, y_end_4, div_num_4)
    y_array_4 = np.round(y_array_4, 2)
    y_list_4 = list(y_array_4)
    
    y_list_side_2 = y_list_1 + y_list_2 + y_list_3 + y_list_4  # 边跨（y轴正半区）y坐标序列定义
    y_list = y_list + y_list_side_2

    support_node_tag_list_1 = list(np.linspace(support_node_tag_list[-1], \
                                                support_node_tag_list[-1]+div_num_1-1, 2).astype('int'))
    support_node_tag_list_2 = list(np.linspace(support_node_tag_list_1[-1], \
                                                support_node_tag_list_1[-1]+div_num_2-1+div_num_3-1, \
                                                    cable_num).astype('int'))
    support_node_tag_list_3 = [support_node_tag_list_2[-1]]
    if y_end_3 != y_end_4:
        support_node_tag_list_3 = list(np.linspace(support_node_tag_list_2[-1], \
                                                    support_node_tag_list_2[-1]+div_num_4-1, 2).astype('int'))
    support_node_tag_list = support_node_tag_list[:-1] + \
                            support_node_tag_list_1[:-1] + support_node_tag_list_2[:-1] + \
                            support_node_tag_list_3
    
    
    # 确定纵曲线圆半径大小
    slope = 0.015  # 直线段1.5%的坡度
    # 非独塔斜拉桥
    if main_span_num > 0:
        girder_radius = np.sqrt((main_span_len / 2) ** 2 + (main_span_len / (2 * slope)) ** 2)
        girder_radius = np.ceil(girder_radius / 100) * 100

    # 独塔斜拉桥
    else:
        girder_radius = np.sqrt(((side_span_len_1 + side_span_len_2) / 2) ** 2 + \
                                ((side_span_len_1 + side_span_len_2) / 2 / slope) ** 2)
        girder_radius = np.ceil(girder_radius / 100) * 100
        
    
    
    
    # =========节点定义=========
    # 节点命名规则：
    # 加劲梁节点采用八位整数命名，千万位为2表示加劲梁结构
    # 百万位和十万位表示所在纵曲线序号（按鱼骨梁形状，自x轴负轴至正轴方向依次为02，01，03）
    # 其余五位为节点序号

    # 非独塔斜拉桥
    if main_span_num > 0:
        half_span_len_sum = side_span_len_1 + main_span_len * main_span_num / 2
        z_shift = girder_z - slope * side_span_len_1  # z坐标偏移值大小
        circle_h_1 = np.sqrt(girder_radius ** 2 - (main_span_len / 2) ** 2)
        # 定义纵梁节点
        for i in range(len(y_list)):
            # 计算z坐标
            y = y_list[i]
            if abs(y) >= (main_span_len / 2):
                # 直线段
                y_0 = - abs(y) + half_span_len_sum
                z = slope * y_0 + z_shift
            else:
                # 圆曲线段
                y_0 = abs(y)
                z_0 = np.sqrt(girder_radius ** 2 - y_0 ** 2) - circle_h_1
                z = z_0 + (half_span_len_sum - main_span_len / 2) * slope + z_shift
        
            node_tag = 20100000 + i + 1
            ops.node(node_tag, 0, y, z)
            skeleton['nodes'][node_tag] = {'crds':[0, y, z], 'mass':None}
            
        
        # 定义虚拟横梁端节点
        for i in range(int((len(y_list)-1)/(insert_node_num+1)+1)):
            y_index =  i * (insert_node_num + 1)
            y = y_list[y_index]
            if abs(y) >= (main_span_len / 2):
                # 直线段
                y_0 = - abs(y) + half_span_len_sum
                z = slope * y_0 + z_shift
            else:
                # 圆曲线段
                y_0 = abs(y)
                z_0 = np.sqrt(girder_radius ** 2 - y_0 ** 2) - circle_h_1
                z = z_0 + (half_span_len_sum - main_span_len / 2) * slope + z_shift
        
            node_tag = 20200000 + y_index + 1
            x = - girder_width / 2
            ops.node(node_tag, x, y, z)
            skeleton['nodes'][node_tag] = {'crds':[x, y, z], 'mass':None}
            
            node_tag = 20300000 + y_index + 1
            x = girder_width / 2
            ops.node(node_tag, x, y, z)
            skeleton['nodes'][node_tag] = {'crds':[x, y, z], 'mass':None}

    # 独塔斜拉桥
    else:
        half_span_len_sum = side_span_len_1 + main_span_len * main_span_num / 2
        circle_h_1 = np.sqrt(girder_radius ** 2 - ((side_span_len_1 + side_span_len_2) / 2) ** 2)
        z_shift = girder_z - (np.sqrt(girder_radius ** 2 - abs((side_span_len_1 + side_span_len_2) / 2 - \
                                                   side_span_len_1) ** 2) - circle_h_1)  # z坐标偏移值大小
        
        # 定义纵梁节点
        for i in range(len(y_list)):
            # 计算z坐标
            y = y_list[i]
            center_shift = side_span_len_1 - (side_span_len_1 + side_span_len_2) / 2
            y_0 = y + center_shift
            z = np.sqrt(girder_radius ** 2 - y_0 ** 2) - circle_h_1 + z_shift
        
            node_tag = 20100000 + i + 1
            ops.node(node_tag, 0, y, z)
            skeleton['nodes'][node_tag] = {'crds':[0, y, z], 'mass':None}
        
        # 定义虚拟横梁端节点
        for i in range(int((len(y_list)-1)/(insert_node_num+1)+1)):
            y_index =  i * (insert_node_num + 1)
            y = y_list[y_index]
            
            # 计算z坐标
            center_shift = side_span_len_1 - (side_span_len_1 + side_span_len_2) / 2
            y_0 = y + center_shift
            z = np.sqrt(girder_radius ** 2 - y_0 ** 2) - circle_h_1 + z_shift
        
            node_tag = 20200000 + y_index + 1
            x = - girder_width / 2
            ops.node(node_tag, x, y, z)
            skeleton['nodes'][node_tag] = {'crds':[x, y, z], 'mass':None}
            
            node_tag = 20300000 + y_index + 1
            x = girder_width / 2
            ops.node(node_tag, x, y, z)
            skeleton['nodes'][node_tag] = {'crds':[x, y, z], 'mass':None}
    
    
    
    
    # =========单元定义=========
    # 截面和坐标系转换方式（仅针对竖向构件）命名规则：
    # 采用七位整数进行命名，百万位为1表示加劲梁，
    # 十万位表示梁的类型（1表示纵梁，2表示虚拟横梁）
    # 对于纵梁，万位表示特殊纵梁及其位置
    # （0表示非特殊纵梁，1表示位于y轴负半区的特殊纵梁，2表示位于y轴正半区的特殊纵梁），其余四位表示顺序号
    # 对于虚拟横梁其余五位表示顺序号
    # 单元命名规则：
    # 加劲梁单元采用八位整数命名，千万位为2表示加劲梁结构
    # 百万位取值为0或1，分别表示单元属于纵梁或横梁
    # 对于纵梁，十万位表示所在纵曲线序号（按鱼骨梁形状，自x轴负轴至正轴方向依次为2，1，3），其余五位表示节点序号
    # 对于横梁，十万位、万位、千位和百位表示横梁序号，其余两位为节点序号（自x轴负轴向正轴方向顺序编号）
    
    sec_info_dict = {}  # 加劲梁截面信息字典（key-截面编号，value-[mp[i], sp[i]]）
    if gravity_index:
        ops.pattern('Plain', load_pattern_tag, time_series_tag)  # 需要进行重力建模时，建立荷载pattern
    
    # 定义第一类纵梁单元信息
    lo_tag_1 = 1100001
    lo_sp = girder_sec_para_1
    lo_mp = girder_mat_para_1
    ops.section('Elastic', lo_tag_1, lo_mp[1], lo_sp[0], lo_sp[1], lo_sp[2], lo_mp[2], lo_sp[3])  # 纵梁截面定义
    skeleton['sections'][lo_tag_1] = {"secType": "elasticSection", "E_mod": lo_mp[1], "area": lo_sp[0], \
                                        "Iz": lo_sp[1], "Iy": lo_sp[2], "Jxx": lo_sp[3], "G_mod": lo_mp[2], \
                                        "rho" : lo_mp[0]}
    
    ops.geomTransf('Linear', lo_tag_1, *[1.0, 0.0, 0.0])  # 纵梁坐标系转换方式定义
    lo_beam_mass_1 = ['-mass', lo_mp[0]*lo_sp[0], '-cMass']  # 纵梁截面质量信息（采用一致质量）
    sec_info_dict[lo_tag_1] = [lo_mp, lo_sp]  # 录入截面信息
    
    # 定义横梁单元信息
    la_tag = 1200001
    la_sp = girder_sec_para_2
    la_mp = girder_mat_para_2
    ops.section('Elastic', la_tag, la_mp[1], la_sp[0], la_sp[1], la_sp[2], la_mp[2], la_sp[3])  # 横梁截面定义
    skeleton['sections'][la_tag] = {"secType": "elasticSection", "E_mod": la_mp[1], "area": la_sp[0], \
                                        "Iz": la_sp[1], "Iy": la_sp[2], "Jxx": la_sp[3], "G_mod": la_mp[2], \
                                        "rho" : la_mp[0]}
    
    ops.geomTransf('Linear', la_tag, *[0.0, -1.0, 0.0])  # 横梁坐标系转换方式定义
    la_beam_mass = ['-mass', la_mp[0]*la_sp[0]+1, '-cMass']  # 横梁截面质量信息（采用一致质量；加上了些微质量，防止质量矩阵病态）
    sec_info_dict[la_tag] = [la_mp, la_sp]  # 录入截面信息
    
    # 定义第二类纵梁单元信息组
    if girder_3_ratio_1 != None:
        lo_tag_2_list = []
        lo_beam_mass_2_list = []
        for i in range(len(girder_3_ratio_1)):
            lo_tag_2 = 1110001 + i
            lo_sp = girder_sec_para_3_1[i]
            lo_mp = girder_mat_para_3_1[i]

            ops.section('Elastic', lo_tag_2, lo_mp[1], lo_sp[0], lo_sp[1], lo_sp[2], lo_mp[2], lo_sp[3])  # 纵梁截面定义
            skeleton['sections'][lo_tag_2] = {"secType": "elasticSection", "E_mod": lo_mp[1], "area": lo_sp[0], \
                                                "Iz": lo_sp[1], "Iy": lo_sp[2], "Jxx": lo_sp[3], "G_mod": lo_mp[2], \
                                                "rho" : lo_mp[0]}
            
            sec_info_dict[lo_tag_2] = [lo_mp, lo_sp]  # 录入截面信息

            ops.geomTransf('Linear', lo_tag_2, *[1.0, 0.0, 0.0])  # 纵梁坐标系转换方式定义
            lo_beam_mass = ['-mass', lo_mp[0]*lo_sp[0], '-cMass']  # 纵梁截面质量信息（采用一致质量）

            lo_tag_2_list.append(lo_tag_2)
            lo_beam_mass_2_list.append(lo_beam_mass)
    
    # 定义第三类纵梁单元信息组
    if girder_3_ratio_2 != None:
        lo_tag_3_list = []
        lo_beam_mass_3_list = []
        for i in range(len(girder_3_ratio_2)):
            lo_tag_3 = 1120001 + i
            lo_sp = girder_sec_para_3_2[i]
            lo_mp = girder_mat_para_3_2[i]

            ops.section('Elastic', lo_tag_3, lo_mp[1], lo_sp[0], lo_sp[1], lo_sp[2], lo_mp[2], lo_sp[3])  # 纵梁截面定义
            skeleton['sections'][lo_tag_3] = {"secType": "elasticSection", "E_mod": lo_mp[1], "area": lo_sp[0], \
                                                "Iz": lo_sp[1], "Iy": lo_sp[2], "Jxx": lo_sp[3], "G_mod": lo_mp[2], \
                                                "rho" : lo_mp[0]}
            
            sec_info_dict[lo_tag_3] = [lo_mp, lo_sp]  # 录入截面信息

            ops.geomTransf('Linear', lo_tag_3, *[1.0, 0.0, 0.0])  # 纵梁坐标系转换方式定义
            lo_beam_mass = ['-mass', lo_mp[0]*lo_sp[0], '-cMass']  # 纵梁截面质量信息（采用一致质量）

            lo_tag_3_list.append(lo_tag_3)
            lo_beam_mass_3_list.append(lo_beam_mass)
    
    
    # 建立纵梁单元
    # 整段加劲梁都是同一种梁型
    if girder_3_ratio_1 == None and girder_3_ratio_2 == None:
        
        temp_girder_G_1 = 0  # 吊索前侧梁段重
        temp_girder_G_2 = 0  # 吊索后侧梁段重
        temp_girder_G_sum = 0  # 累计梁单元重

        temp_moment_inertia_list = [0, 0]  # 单元转动惯量值（[i节点，j节点]）

        for i in range(len(y_list)-1):
            lo_ele_tag = 20100000 + i + 1
            node_1_tag = lo_ele_tag
            node_2_tag = node_1_tag + 1

            sec_tag = lo_tag_1
            trans_tag = lo_tag_1
            lo_beam_mass = lo_beam_mass_1

            ops.element('elasticBeamColumn', lo_ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *lo_beam_mass)
            skeleton['elements'][lo_ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}

            # 记录拉索竖向吊重
            ele_len = element_len_cal(node_1_tag, node_2_tag)
            ele_G = 9.8 * ele_len * \
                    sec_info_dict[sec_tag][0][0] * sec_info_dict[sec_tag][1][0]
            
            temp_girder_G_sum += ele_G
            if (i+2) in support_node_tag_list:
                if (i+2) == support_node_tag_list[1]:
                    temp_girder_G_1 = temp_girder_G_sum
                    temp_girder_G_sum = 0
                    if no_anchor_num_side_1 == 0:
                        girder_G_list.append(temp_girder_G_1/2)
                elif (i+2) == support_node_tag_list[-1]:
                    temp_girder_G_2 = temp_girder_G_1
                    temp_girder_G_1 = temp_girder_G_sum
                    girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                    temp_girder_G_sum = 0
                    if no_anchor_num_side_2 == 0:
                        girder_G_list.append(temp_girder_G_2/2)
                else:
                    temp_girder_G_2 = temp_girder_G_1
                    temp_girder_G_1 = temp_girder_G_sum
                    girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                    temp_girder_G_sum = 0

            # 校正加劲梁转动惯量
            moment_of_inertia_correct(i, temp_moment_inertia_list, ele_len, \
                                      sec_info_dict, sec_tag, \
                                        len(y_list), node_1_tag, node_2_tag, \
                                        skeleton)

            # 重力荷载建立
            if gravity_index:
                element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                          node_1_tag, node_2_tag)
            
    # 加劲梁两个边跨都存在混合梁型
    elif girder_3_ratio_1 != None and girder_3_ratio_2 != None:
        
        temp_girder_G_1 = 0  # 吊索前侧梁段重
        temp_girder_G_2 = 0  # 吊索后侧梁段重
        temp_girder_G_sum = 0  # 累计梁单元重

        temp_moment_inertia_list = [0, 0]  # 单元转动惯量值（[i节点，j节点]）

        for i in range(len(y_list)-1):
            lo_ele_tag = 20100000 + i + 1
            node_1_tag = lo_ele_tag
            node_2_tag = node_1_tag + 1
            
            # 对于第一个节点在y轴负半区的单元
            if ops.nodeCoord(node_1_tag)[1] < 0:
                len_ratio_1 = (y_shift + ops.nodeCoord(node_2_tag)[1]) / side_span_len_1                
                sec_tag = lo_tag_1
                trans_tag = lo_tag_1
                lo_beam_mass = lo_beam_mass_1
                # 判断该单元是否位于某段特殊段
                for j in range(len(girder_3_ratio_1)):
                    if len_ratio_1 >= girder_3_ratio_1[j][0] and len_ratio_1 <= girder_3_ratio_1[j][1]:
                        sec_tag = lo_tag_2_list[j]
                        trans_tag = lo_tag_2_list[j]
                        lo_beam_mass = lo_beam_mass_2_list[j]
                        break
                ops.element('elasticBeamColumn', lo_ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *lo_beam_mass)
                skeleton['elements'][lo_ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                    "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}

                # 记录拉索竖向吊重
                ele_len = element_len_cal(node_1_tag, node_2_tag)
                ele_G = 9.8 * ele_len * \
                        sec_info_dict[sec_tag][0][0] * sec_info_dict[sec_tag][1][0]
                
                temp_girder_G_sum += ele_G
                if (i+2) in support_node_tag_list:
                    if (i+2) == support_node_tag_list[1]:
                        temp_girder_G_1 = temp_girder_G_sum
                        temp_girder_G_sum = 0
                        if no_anchor_num_side_1 == 0:
                            girder_G_list.append(temp_girder_G_1/2)
                    elif (i+2) == support_node_tag_list[-1]:
                        temp_girder_G_2 = temp_girder_G_1
                        temp_girder_G_1 = temp_girder_G_sum
                        girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                        temp_girder_G_sum = 0
                        if no_anchor_num_side_2 == 0:
                            girder_G_list.append(temp_girder_G_2/2)
                    else:
                        temp_girder_G_2 = temp_girder_G_1
                        temp_girder_G_1 = temp_girder_G_sum
                        girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                        temp_girder_G_sum = 0

                # 校正加劲梁转动惯量
                moment_of_inertia_correct(i, temp_moment_inertia_list, ele_len, \
                                        sec_info_dict, sec_tag, \
                                            len(y_list), node_1_tag, node_2_tag, \
                                            skeleton)

                # 重力荷载建立
                if gravity_index:
                    element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                            node_1_tag, node_2_tag)
            
            # 对于第一个节点在y轴正半区的单元
            else:
                len_ratio_2 = (main_span_len * main_span_num / 2 + side_span_len_2 - \
                           ops.nodeCoord(node_1_tag)[1]) / side_span_len_2
                sec_tag = lo_tag_1
                trans_tag = lo_tag_1
                lo_beam_mass = lo_beam_mass_1
                # 判断该单元是否位于某段特殊段
                for j in range(len(girder_3_ratio_2)):
                    if len_ratio_2 >= girder_3_ratio_2[j][0] and len_ratio_2 <= girder_3_ratio_2[j][1]:
                        sec_tag = lo_tag_3_list[j]
                        trans_tag = lo_tag_3_list[j]
                        lo_beam_mass = lo_beam_mass_3_list[j]
                        break
                ops.element('elasticBeamColumn', lo_ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *lo_beam_mass)
                skeleton['elements'][lo_ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                    "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}

                # 记录拉索竖向吊重
                ele_len = element_len_cal(node_1_tag, node_2_tag)
                ele_G = 9.8 * ele_len * \
                        sec_info_dict[sec_tag][0][0] * sec_info_dict[sec_tag][1][0]
                
                temp_girder_G_sum += ele_G
                if (i+2) in support_node_tag_list:
                    if (i+2) == support_node_tag_list[1]:
                        temp_girder_G_1 = temp_girder_G_sum
                        temp_girder_G_sum = 0
                        if no_anchor_num_side_1 == 0:
                            girder_G_list.append(temp_girder_G_1/2)
                    elif (i+2) == support_node_tag_list[-1]:
                        temp_girder_G_2 = temp_girder_G_1
                        temp_girder_G_1 = temp_girder_G_sum
                        girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                        temp_girder_G_sum = 0
                        if no_anchor_num_side_2 == 0:
                            girder_G_list.append(temp_girder_G_2/2)
                    else:
                        temp_girder_G_2 = temp_girder_G_1
                        temp_girder_G_1 = temp_girder_G_sum
                        girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                        temp_girder_G_sum = 0

                # 校正加劲梁转动惯量
                moment_of_inertia_correct(i, temp_moment_inertia_list, ele_len, \
                                        sec_info_dict, sec_tag, \
                                            len(y_list), node_1_tag, node_2_tag, \
                                            skeleton)

                # 重力荷载建立
                if gravity_index:
                    element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                            node_1_tag, node_2_tag)

    # 仅加劲梁y轴负半区边跨存在混合梁型        
    elif girder_3_ratio_1 != None:
        
        temp_girder_G_1 = 0  # 吊索前侧梁段重
        temp_girder_G_2 = 0  # 吊索后侧梁段重
        temp_girder_G_sum = 0  # 累计梁单元重

        temp_moment_inertia_list = [0, 0]  # 单元转动惯量值（[i节点，j节点]）
        
        for i in range(len(y_list)-1):
            lo_ele_tag = 20100000 + i + 1
            node_1_tag = lo_ele_tag
            node_2_tag = node_1_tag + 1
            
            # 对于第一个节点在y轴负半区的单元
            if ops.nodeCoord(node_1_tag)[1] < 0:
                len_ratio_1 = (y_shift + ops.nodeCoord(node_2_tag)[1]) / side_span_len_1                
                sec_tag = lo_tag_1
                trans_tag = lo_tag_1
                lo_beam_mass = lo_beam_mass_1
                # 判断该单元是否位于某段特殊段
                for j in range(len(girder_3_ratio_1)):
                    if len_ratio_1 >= girder_3_ratio_1[j][0] and len_ratio_1 <= girder_3_ratio_1[j][1]:
                        sec_tag = lo_tag_2_list[j]
                        trans_tag = lo_tag_2_list[j]
                        lo_beam_mass = lo_beam_mass_2_list[j]
                        break
                ops.element('elasticBeamColumn', lo_ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *lo_beam_mass)
                skeleton['elements'][lo_ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                    "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}

                # 记录拉索竖向吊重
                ele_len = element_len_cal(node_1_tag, node_2_tag)
                ele_G = 9.8 * ele_len * \
                        sec_info_dict[sec_tag][0][0] * sec_info_dict[sec_tag][1][0]
                
                temp_girder_G_sum += ele_G
                if (i+2) in support_node_tag_list:
                    if (i+2) == support_node_tag_list[1]:
                        temp_girder_G_1 = temp_girder_G_sum
                        temp_girder_G_sum = 0
                        if no_anchor_num_side_1 == 0:
                            girder_G_list.append(temp_girder_G_1/2)
                    elif (i+2) == support_node_tag_list[-1]:
                        temp_girder_G_2 = temp_girder_G_1
                        temp_girder_G_1 = temp_girder_G_sum
                        girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                        temp_girder_G_sum = 0
                        if no_anchor_num_side_2 == 0:
                            girder_G_list.append(temp_girder_G_2/2)
                    else:
                        temp_girder_G_2 = temp_girder_G_1
                        temp_girder_G_1 = temp_girder_G_sum
                        girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                        temp_girder_G_sum = 0

                # 校正加劲梁转动惯量
                moment_of_inertia_correct(i, temp_moment_inertia_list, ele_len, \
                                        sec_info_dict, sec_tag, \
                                            len(y_list), node_1_tag, node_2_tag, \
                                            skeleton)

                # 重力荷载建立
                if gravity_index:
                    ele_len = element_len_cal(node_1_tag, node_2_tag)
                    element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                            node_1_tag, node_2_tag)
            
            # 对于第一个节点在y轴正半区的单元
            else:
                sec_tag = lo_tag_1
                trans_tag = lo_tag_1
                lo_beam_mass = lo_beam_mass_1
                ops.element('elasticBeamColumn', lo_ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *lo_beam_mass)
                skeleton['elements'][lo_ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                    "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}

                # 记录拉索竖向吊重
                ele_len = element_len_cal(node_1_tag, node_2_tag)
                ele_G = 9.8 * ele_len * \
                        sec_info_dict[sec_tag][0][0] * sec_info_dict[sec_tag][1][0]
                
                temp_girder_G_sum += ele_G
                if (i+2) in support_node_tag_list:
                    if (i+2) == support_node_tag_list[1]:
                        temp_girder_G_1 = temp_girder_G_sum
                        temp_girder_G_sum = 0
                        if no_anchor_num_side_1 == 0:
                            girder_G_list.append(temp_girder_G_1/2)
                    elif (i+2) == support_node_tag_list[-1]:
                        temp_girder_G_2 = temp_girder_G_1
                        temp_girder_G_1 = temp_girder_G_sum
                        girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                        temp_girder_G_sum = 0
                        if no_anchor_num_side_2 == 0:
                            girder_G_list.append(temp_girder_G_2/2)
                    else:
                        temp_girder_G_2 = temp_girder_G_1
                        temp_girder_G_1 = temp_girder_G_sum
                        girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                        temp_girder_G_sum = 0

                # 校正加劲梁转动惯量
                moment_of_inertia_correct(i, temp_moment_inertia_list, ele_len, \
                                        sec_info_dict, sec_tag, \
                                            len(y_list), node_1_tag, node_2_tag, \
                                            skeleton)

                # 重力荷载建立
                if gravity_index:
                    ele_len = element_len_cal(node_1_tag, node_2_tag)
                    element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                            node_1_tag, node_2_tag)
    
    # 仅加劲梁y轴正半区边跨存在混合梁型
    else:
        
        temp_girder_G_1 = 0  # 吊索前侧梁段重
        temp_girder_G_2 = 0  # 吊索后侧梁段重
        temp_girder_G_sum = 0  # 累计梁单元重

        temp_moment_inertia_list = [0, 0]  # 单元转动惯量值（[i节点，j节点]）

        for i in range(len(y_list)-1):
            lo_ele_tag = 20100000 + i + 1
            node_1_tag = lo_ele_tag
            node_2_tag = node_1_tag + 1
            
            # 对于第一个节点在y轴负半区的单元
            if ops.nodeCoord(node_1_tag)[1] < 0:              
                sec_tag = lo_tag_1
                trans_tag = lo_tag_1
                lo_beam_mass = lo_beam_mass_1
                ops.element('elasticBeamColumn', lo_ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *lo_beam_mass)
                skeleton['elements'][lo_ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                    "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}

                # 记录拉索竖向吊重
                ele_len = element_len_cal(node_1_tag, node_2_tag)
                ele_G = 9.8 * ele_len * \
                        sec_info_dict[sec_tag][0][0] * sec_info_dict[sec_tag][1][0]
                
                temp_girder_G_sum += ele_G
                if (i+2) in support_node_tag_list:
                    if (i+2) == support_node_tag_list[1]:
                        temp_girder_G_1 = temp_girder_G_sum
                        temp_girder_G_sum = 0
                        if no_anchor_num_side_1 == 0:
                            girder_G_list.append(temp_girder_G_1/2)
                    elif (i+2) == support_node_tag_list[-1]:
                        temp_girder_G_2 = temp_girder_G_1
                        temp_girder_G_1 = temp_girder_G_sum
                        girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                        temp_girder_G_sum = 0
                        if no_anchor_num_side_2 == 0:
                            girder_G_list.append(temp_girder_G_2/2)
                    else:
                        temp_girder_G_2 = temp_girder_G_1
                        temp_girder_G_1 = temp_girder_G_sum
                        girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                        temp_girder_G_sum = 0

                # 校正加劲梁转动惯量
                moment_of_inertia_correct(i, temp_moment_inertia_list, ele_len, \
                                        sec_info_dict, sec_tag, \
                                            len(y_list), node_1_tag, node_2_tag, \
                                            skeleton)

                # 重力荷载建立
                if gravity_index:
                    element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                            node_1_tag, node_2_tag)
            
            # 对于第一个节点在y轴正半区的单元
            else:
                len_ratio_2 = (main_span_len * main_span_num / 2 + side_span_len_2 - \
                           ops.nodeCoord(node_1_tag)[1]) / side_span_len_2
                sec_tag = lo_tag_1
                trans_tag = lo_tag_1
                lo_beam_mass = lo_beam_mass_1
                # 判断该单元是否位于某段特殊段
                for j in range(len(girder_3_ratio_2)):
                    if len_ratio_2 >= girder_3_ratio_2[j][0] and len_ratio_2 <= girder_3_ratio_2[j][1]:
                        sec_tag = lo_tag_3_list[j]
                        trans_tag = lo_tag_3_list[j]
                        lo_beam_mass = lo_beam_mass_3_list[j]
                        break
                ops.element('elasticBeamColumn', lo_ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *lo_beam_mass)
                skeleton['elements'][lo_ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                    "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}

                # 记录拉索竖向吊重
                ele_len = element_len_cal(node_1_tag, node_2_tag)
                ele_G = 9.8 * ele_len * \
                        sec_info_dict[sec_tag][0][0] * sec_info_dict[sec_tag][1][0]
                
                temp_girder_G_sum += ele_G
                if (i+2) in support_node_tag_list:
                    if (i+2) == support_node_tag_list[1]:
                        temp_girder_G_1 = temp_girder_G_sum
                        temp_girder_G_sum = 0
                        if no_anchor_num_side_1 == 0:
                            girder_G_list.append(temp_girder_G_1/2)
                    elif (i+2) == support_node_tag_list[-1]:
                        temp_girder_G_2 = temp_girder_G_1
                        temp_girder_G_1 = temp_girder_G_sum
                        girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                        temp_girder_G_sum = 0
                        if no_anchor_num_side_2 == 0:
                            girder_G_list.append(temp_girder_G_2/2)
                    else:
                        temp_girder_G_2 = temp_girder_G_1
                        temp_girder_G_1 = temp_girder_G_sum
                        girder_G_list.append((temp_girder_G_1+temp_girder_G_2)/2)
                        temp_girder_G_sum = 0

                # 校正加劲梁转动惯量
                moment_of_inertia_correct(i, temp_moment_inertia_list, ele_len, \
                                        sec_info_dict, sec_tag, \
                                            len(y_list), node_1_tag, node_2_tag, \
                                            skeleton)

                # 重力荷载建立
                if gravity_index:
                    element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                            node_1_tag, node_2_tag)
    
    
    # 建立横梁单元
    for i in range(int((len(y_list)-1)/(insert_node_num+1)+1)):
        node_index =  i * (insert_node_num + 1)
        la_ele_tag_1 = 21000000 + (i + 1) * 100 + 1
        la_ele_tag_2 = 21000000 + (i + 1) * 100 + 2
        node_1_tag = 20200000 + node_index + 1
        node_2_tag = 20100000 + node_index + 1
        node_3_tag = 20300000 + node_index + 1
        sec_tag = la_tag
        trans_tag = la_tag
        ops.element('elasticBeamColumn', la_ele_tag_1, node_1_tag, node_2_tag, sec_tag, trans_tag, *la_beam_mass)
        skeleton['elements'][la_ele_tag_1] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                            "vecxz": [0.0, -1.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}
        
        ops.element('elasticBeamColumn', la_ele_tag_2, node_2_tag, node_3_tag, sec_tag, trans_tag, *la_beam_mass)
        skeleton['elements'][la_ele_tag_2] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_2_tag, node_3_tag], \
                                            "vecxz": [0.0, -1.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}
    
    
    div_num_list = [anchor_densed_num_1, anchor_densed_num_2, no_anchor_num_side_1, no_anchor_num_side_2, \
                    no_anchor_num_tower, no_anchor_num_middle]
        
    # 处理girder_G_list
    new_girder_G_list = []
    for i in range(int(main_span_num*2+2)):
        temp_G_list = []
        for j in range(cable_num):
            temp_G_list.append(girder_G_list[0])
            girder_G_list = girder_G_list[1:]
        new_girder_G_list.append(temp_G_list)
        temp_G_list = []
        if i % 2 == 0:
            girder_G_list = girder_G_list[1:]
    
    girder_G_list = new_girder_G_list
    
    return div_num_list, girder_G_list




# 主塔建模
def towers_modelling(tower_num, center_loc, key_node_para_0, cable_num, \
                      col_sec_para, col_mat_para, tower_div_num, \
                      skeleton, \
                      gravity_index=0, load_pattern_tag=-1, time_series_tag=-1, \
                      beam_sec_para_1=None, beam_mat_para_1=None, beam_div_num_1=-10, \
                      beam_sec_para_2=None, beam_mat_para_2=None, beam_div_num_2=-10):
    
    # =========主塔有限元建模=========
    # 数据格式：
    # tower_num = 主塔序号（按照y方向由负区至正区由1开始依次编排）
    # center_loc = 主塔中心投影点坐标（全局坐标系下） = [x, y, z]
    #
    # key_node_para = 关键节点参数 = [
    #                                 [[节点1-x坐标, 节点1-y坐标, 节点1-z坐标], 节点1是否布置横桥向横梁, 
    #                                  节点1是否布置顺桥向横梁, 节点1拉索布置状态], 
    #                                [节点2...], ...
    #                                ]
    #    “关键节点”仅考虑主塔的第1支（考虑到常规主塔的对称性），同时需要保证每相邻两个关键节点间的结构状态均为直线
    #    “节点坐标”的坐标系为主塔平面坐标系，原点取主塔中线与柱脚水平线交点，横桥向为x方向，竖向为y方向
    #    “是否布置横梁”取值为0或1，0表示该点位不布置横梁，1表示该点位布置横梁
    #    “拉索布置状态”取值为-1、0和1，-1表示该点即非拉索锚固区起始点也非结束点，0表示为结束点，1表示为起始点
    #
    # cable_num = 单侧拉索根数
    #
    # col_sec_para = 主塔竖向构件截面参数 = [[区段1截面积，区段1-Iz，区段1-Iy，区段1-Jxx], [区段2...], ...]
    # col_mat_para = 主塔竖向构件材料参数 = [[区段1材料密度，区段1材料弹性模量，区段1材料剪切模量], [区段2...], ...]
    # *“区段”指由各关键节点划分出的各节段，数组中按高度由低到高依次排列
    #
    # tower_div_num = 主塔竖向节段划分数量参考值
    # 
    # skeleton = 桥梁骨架信息
    # 
    # load_pattern_tag = 荷载pattern编号
    # time_series_tag = 时间序列序号
    # gravity_index = 主塔建模是否同时进行重力荷载建模
    #
    # beam_sec_para_1 = 主塔横桥向横梁截面参数 = [[横梁1截面积，横梁1-Iz，横梁1-Iy，横梁1-Jxx], [横梁2...], ...]
    # beam_mat_para_1 = 主塔横桥向横梁材料参数 = [[横梁1材料密度，横梁1材料弹性模量，横梁1材料剪切模量], [横梁2...], ...]
    # beam_div_num_1 = 横桥向横梁节段划分数量参考值
    #
    # beam_sec_para_2 = 主塔顺桥向横梁截面参数 = [[横梁1截面积，横梁1-Iz，横梁1-Iy，横梁1-Jxx], [横梁2...], ...]
    # beam_mat_para_2 = 主塔顺桥向横梁材料参数 = [[横梁1材料密度，横梁1材料弹性模量，横梁1材料剪切模量], [横梁2...], ...]
    # beam_div_num_2 = 顺桥向横梁节段划分数量参考值
    # *以上横梁参数数组元素排序均按照横梁高度由低到高进行
    
    
    # =========节点定义=========
    # 节点命名规则：
    # 若主塔存在对称的四支，以第三象限一支为第1支，其他支按顺时针方向依次编号
    # 若发生主塔分支的合并，统一将合并后分支的编号归为号数更小的一支
    # 主塔节点采用八位整数命名，千万位为1表示主塔结构，百万位与十万位表示主塔序号，
    # 万位表示属于竖向构件还是横梁（0为竖向构件，1为横桥向横梁，2为顺桥向横梁），
    # 千位表示主塔分支序号或横梁序号，其余三位为节点序号
    # 横梁序号和节点序号均按照高度由塔底至塔顶由1依次递增
    
    key_node_para = copy.deepcopy(key_node_para_0)
    
    tower_div_h = key_node_para[-1][0][2] / tower_div_num  # 计算主塔节段长度参考值
    
    # 将主塔的关键节点坐标移动至世界坐标系
    for i in range(len(key_node_para)):
        key_node_para[i][0][0] = key_node_para[i][0][0] + center_loc[0]
        key_node_para[i][0][1] = key_node_para[i][0][1] + center_loc[1]
        key_node_para[i][0][2] = key_node_para[i][0][2] + center_loc[2]
    
    # 计算拉索锚固区各节点的x和z坐标（第1支）
    anchor_x_1 = 0  # 锚固区起点x坐标
    anchor_x_0 = 0  # 锚固区终点x坐标
    anchor_y_1 = 0  # 锚固区起点y坐标
    anchor_y_0 = 0  # 锚固区终点y坐标
    anchor_z_1 = 0  # 锚固区起点z坐标
    anchor_z_0 = 0  # 锚固区终点z坐标
    for i in range(len(key_node_para)):
        if key_node_para[i][-1] == 1:
            anchor_x_1 = key_node_para[i][0][0]
            anchor_y_1 = key_node_para[i][0][1]
            anchor_z_1 = key_node_para[i][0][2]
        elif key_node_para[i][-1] == 0:
            anchor_x_0 = key_node_para[i][0][0]
            anchor_y_0 = key_node_para[i][0][1]
            anchor_z_0 = key_node_para[i][0][2]
    
    anchor_x_interval = np.linspace(anchor_x_1, anchor_x_0, int(cable_num)+2)  # 锚固区节点x坐标
    anchor_y_interval = np.linspace(anchor_y_1, anchor_y_0, int(cable_num)+2)  # 锚固区节点y坐标
    anchor_z_interval = np.linspace(anchor_z_1, anchor_z_0, int(cable_num)+2)  # 锚固区节点z坐标
    
    anchor_x_interval = np.round(anchor_x_interval, 2)
    anchor_y_interval = np.round(anchor_y_interval, 2)
    anchor_z_interval = np.round(anchor_z_interval, 2)
    
    
    # 1 逐段定义竖向构件节点
    first_node_tag = 10001001 + tower_num * 100000  # 当前主塔的第1支分支竖向构件的第1个节点
    node_count = 0  # 累计已建立的节点数量(第1支)
    
    key_nodes = []  # 关键节点序号数组
    anchor_nodes_range = []  # 锚固区起止序号数组
    no_anchor_nodes = []  # 锚固区非锚点序号数组
    beam_nodes_1 = []  # 横桥向横梁节点序号数组
    beam_nodes_2 = []  # 顺桥向横梁节点序号数组
    
    anchor_index = 0  # 判断是否位于锚固区的指标变量
    
    # 逐个关键节点间段落进行节点建立
    for i in range(len(key_node_para) - 1):
                
        # 1-1 当前节点为非锚固区关键节点或锚固区终止节点时
        # 分起始节点和中间段节点两部分进行建立，各有4种情况
        if (key_node_para[i][-1] == -1 and anchor_index == 0) or \
            key_node_para[i][-1] == 0:
            
            delta_z = key_node_para[i+1][0][2] - key_node_para[i][0][2]  # 当前节点与下一节点的高差
            extra_node_num = delta_z // tower_div_h  # 两个关键节点间应该插入的节点数量
            extra_node_num = int(extra_node_num)

            x_interval = np.linspace(key_node_para[i][0][0], key_node_para[i+1][0][0], extra_node_num+2)
            x_interval = np.round(x_interval, 2)  # 两个关键节点及之间所有节点的x坐标序列
            
            y_interval = np.linspace(key_node_para[i][0][1], key_node_para[i+1][0][1], extra_node_num+2)
            y_interval = np.round(y_interval, 2)  # 两个关键节点及之间所有节点的y坐标序列
            
            z_interval = np.linspace(key_node_para[i][0][2], key_node_para[i+1][0][2], extra_node_num+2)
            z_interval = np.round(z_interval, 2)  # 两个关键节点及之间所有节点的z坐标序列
            
            for j in range(extra_node_num + 1):
                
                # 1-1-1 起始节点建立
                if j == 0:
                    # 第1支(1个共同起始节点)
                    if key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] == center_loc[1]:

                        node_tag_1 = first_node_tag + node_count  # 共起始节点编号
                        node_x_1 = key_node_para[i][0][0]  # 共起始节点x坐标
                        node_y_1 = key_node_para[i][0][1]  # 共起始节点y坐标
                        node_z_1 = key_node_para[i][0][2] # 共起始节点z坐标
                        
                        node_z_1 = np.round(node_z_1, 2)  # 可不需要
                        
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_count += 1
                        
                        key_nodes.append(node_count)  # 存储关键节点编号
                        if key_node_para[i][-1] == 0:
                            anchor_nodes_range.append(node_count)  # 存储锚固区终止节点编号
                            anchor_index = 0  # 退出锚固区
                    
                    # 第1支+第2支（左右2个起始节点）
                    elif key_node_para[i][0][0] != center_loc[0] and key_node_para[i][0][1] == center_loc[1]:

                        node_tag_1 = first_node_tag + node_count  # 第1支的起始节点编号
                        node_x_1 = key_node_para[i][0][0]  # 第1支的起始节点x坐标
                        node_y_1 = key_node_para[i][0][1]  # 第1支的起始节点y坐标
                        node_z_1 = key_node_para[i][0][2]  # 第1支的起始节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_2 = first_node_tag + node_count + 1000  # 第2支的起始节点编号
                        node_x_2 = 2 * center_loc[0] - key_node_para[i][0][0]  # 第2支的起始节点x坐标
                        node_y_2 = key_node_para[i][0][1]  # 第2支的起始节点y坐标
                        node_z_2 = key_node_para[i][0][2]  # 第2支的起始节点z坐标
                        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
                        
                        node_count += 1
                        
                        key_nodes.append(node_count)  # 存储关键节点编号
                        if key_node_para[i][-1] == 0:
                            anchor_nodes_range.append(node_count)  # 存储锚固区终止节点编号
                            anchor_index = 0  # 退出锚固区
                        if key_node_para[i][1] == 1:
                            beam_nodes_1.append(node_count)  # 存储横桥向横梁节点编号
                    
                    # 第1支+第3支（上下2个起始节点）
                    elif key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] != center_loc[1]:

                        node_tag_1 = first_node_tag + node_count  # 第1支的起始节点编号
                        node_x_1 = key_node_para[i][0][0]  # 第1支的起始节点x坐标
                        node_y_1 = key_node_para[i][0][1]  # 第1支的起始节点y坐标
                        node_z_1 = key_node_para[i][0][2]  # 第1支的起始节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_3 = first_node_tag + node_count + 2000  # 第3支的起始节点编号
                        node_x_3 = 2 * center_loc[0] - key_node_para[i][0][0]  # 第3支的起始节点x坐标
                        node_y_3 = 2 * center_loc[1] - key_node_para[i][0][1]  # 第3支的起始节点y坐标
                        node_z_3 = key_node_para[i][0][2]  # 第3支的起始节点z坐标
                        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
                        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}
                        
                        node_count += 1
                        
                        key_nodes.append(node_count)  # 存储关键节点编号
                        if key_node_para[i][-1] == 0:
                            anchor_nodes_range.append(node_count)  # 存储锚固区终止节点编号
                            anchor_index = 0  # 退出锚固区
                        if key_node_para[i][2] == 1:
                            beam_nodes_2.append(node_count)  # 存储顺桥向横梁节点编号
                    
                    # 4支均有独立起始节点
                    else:

                        node_tag_1 = first_node_tag + node_count  # 第1支的起始节点编号
                        node_x_1 = key_node_para[i][0][0]  # 第1支的起始节点x坐标
                        node_y_1 = key_node_para[i][0][1]  # 第1支的起始节点y坐标
                        node_z_1 = key_node_para[i][0][2]  # 第1支的起始节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_2 = first_node_tag + node_count + 1000  # 第2支的起始节点编号
                        node_x_2 = 2 * center_loc[0] - key_node_para[i][0][0]  # 第2支的起始节点x坐标
                        node_y_2 = key_node_para[i][0][1]  # 第2支的起始节点y坐标
                        node_z_2 = key_node_para[i][0][2]  # 第2支的起始节点z坐标
                        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
                        
                        node_tag_3 = first_node_tag + node_count + 2000  # 第3支的起始节点编号
                        node_x_3 = 2 * center_loc[0] - key_node_para[i][0][0]  # 第3支的起始节点x坐标
                        node_y_3 = 2 * center_loc[1] - key_node_para[i][0][1]  # 第3支的起始节点y坐标
                        node_z_3 = key_node_para[i][0][2]  # 第3支的起始节点z坐标
                        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
                        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}
                        
                        node_tag_4 = first_node_tag + node_count + 3000  # 第4支的起始节点编号
                        node_x_4 = key_node_para[i][0][0]  # 第4支的起始节点x坐标
                        node_y_4 = 2 * center_loc[1] - key_node_para[i][0][1]  # 第4支的起始节点y坐标
                        node_z_4 = key_node_para[i][0][2]  # 第4支的起始节点z坐标
                        ops.node(node_tag_4, node_x_4, node_y_4, node_z_4)
                        skeleton['nodes'][node_tag_4] = {'crds':[node_x_4, node_y_4, node_z_4], 'mass':None}
                        
                        node_count += 1
                        
                        key_nodes.append(node_count)  # 存储关键节点编号
                        if key_node_para[i][-1] == 0:
                            anchor_nodes_range.append(node_count)  # 存储锚固区终止节点编号
                            anchor_index = 0  # 退出锚固区
                        if key_node_para[i][1] == 1:
                            beam_nodes_1.append(node_count)  # 存储横桥向横梁节点编号
                        if key_node_para[i][2] == 1:
                            beam_nodes_2.append(node_count)  # 存储顺桥向横梁节点编号
                        
                        
                # 1-1-2 其余节点建立
                else:
                    # 整个节段只有竖向1支
                    if (key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] == center_loc[1]) and \
                        (key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]):

                        node_tag_1 = first_node_tag + node_count  # 共节点编号
                        node_x_1 = x_interval[j]  # 共节点x坐标
                        node_y_1 = y_interval[j]  # 共节点y坐标
                        node_z_1 = z_interval[j]  # 共节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_count += 1
                    
                    # 第1支+第2支（左右,3种组合情况）
                    elif ((key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] == center_loc[1]) and \
                            (key_node_para[i+1][0][0] != center_loc[0] and key_node_para[i+1][0][1] == center_loc[1])) \
                            or \
                            ((key_node_para[i][0][0] != center_loc[0] and key_node_para[i][0][1] == center_loc[1]) and \
                            ((key_node_para[i+1][0][0] != center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]) or \
                            (key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]))):
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支的节点编号
                        node_x_1 = x_interval[j]  # 第1支的节点x坐标
                        node_y_1 = y_interval[j]  # 第1支的节点y坐标
                        node_z_1 = z_interval[j]  # 第1支的节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_2 = first_node_tag + node_count + 1000  # 第2支的节点编号
                        node_x_2 = 2 * center_loc[0] - x_interval[j]  # 第2支的节点x坐标
                        node_y_2 = y_interval[j]  # 第2支的节点y坐标
                        node_z_2 = z_interval[j]  # 第2支的节点z坐标
                        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
                        
                        node_count += 1
                        
                    # 第1支+第3支（上下,3种组合情况）
                    elif ((key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] == center_loc[1]) and \
                            (key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] != center_loc[1])) \
                            or \
                            ((key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] != center_loc[1]) and \
                            ((key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] != center_loc[1]) or \
                            (key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]))):
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支的起始节点编号
                        node_x_1 = x_interval[j]  # 第1支的节点x坐标
                        node_y_1 = y_interval[j]  # 第1支的节点y坐标
                        node_z_1 = z_interval[j]  # 第1支的节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_3 = first_node_tag + node_count + 2000  # 第3支的起始节点编号
                        node_x_3 = 2 * center_loc[0] - x_interval[j]  # 第3支的节点x坐标
                        node_y_3 = 2 * center_loc[1] - y_interval[j]  # 第3支的节点y坐标
                        node_z_3 = z_interval[j]  # 第3支的节点z坐标
                        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
                        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}
                        
                        node_count += 1
                        
                    # 4支均存在
                    else:
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支的起始节点编号
                        node_x_1 = x_interval[j]  # 第1支的节点x坐标
                        node_y_1 = y_interval[j]  # 第1支的节点y坐标
                        node_z_1 = z_interval[j]  # 第1支的节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_2 = first_node_tag + node_count + 1000  # 第2支的节点编号
                        node_x_2 = 2 * center_loc[0] - x_interval[j]  # 第2支的节点x坐标
                        node_y_2 = y_interval[j]  # 第2支的节点y坐标
                        node_z_2 = z_interval[j]  # 第2支的节点z坐标
                        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
                        
                        node_tag_3 = first_node_tag + node_count + 2000  # 第3支的节点编号
                        node_x_3 = 2 * center_loc[0] - x_interval[j]  # 第3支的节点x坐标
                        node_y_3 = 2 * center_loc[1] - y_interval[j]  # 第3支的节点y坐标
                        node_z_3 = z_interval[j]  # 第3支的节点z坐标
                        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
                        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}
                        
                        node_tag_4 = first_node_tag + node_count + 3000  # 第4支的节点编号
                        node_x_4 = x_interval[j]  # 第4支的节点x坐标
                        node_y_4 = 2 * center_loc[1] - y_interval[j]  # 第4支的节点y坐标
                        node_z_4 = z_interval[j]  # 第4支的节点z坐标
                        ops.node(node_tag_4, node_x_4, node_y_4, node_z_4)
                        skeleton['nodes'][node_tag_4] = {'crds':[node_x_4, node_y_4, node_z_4], 'mass':None}
                        
                        node_count += 1
                                
        
        # 1-2 当前节点为锚固区起始节点时
        # 分起始节点和中间段节点两部分进行建立，各有4种情况
        elif key_node_para[i][-1] == 1:
            
            anchor_index = 1  # 进入锚固区
            
            anchor_num_rest = len(anchor_z_interval) - 1  # 尚未建模的锚固节点
            for j in range(anchor_num_rest):
                
                # 1-2-1 起始节点建立
                if j == 0:
                    
                    # 第1支(1个共同起始节点)
                    if key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] == center_loc[1]:
                        
                        node_tag_1 = first_node_tag + node_count  # 共起始节点编号
                        node_x_1 = key_node_para[i][0][0]  # 共起始节点x坐标
                        node_y_1 = key_node_para[i][0][1]  # 共起始节点y坐标
                        node_z_1 = key_node_para[i][0][2] # 共起始节点z坐标
                        node_z_1 = np.round(node_z_1, 2)
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_count += 1
                        
                        key_nodes.append(node_count)  # 存储关键节点编号
                        anchor_nodes_range.append(node_count)  # 存储锚固区起始节点编号
                        
                    # 第1支+第2支（左右2个起始节点）
                    elif key_node_para[i][0][0] != center_loc[0] and key_node_para[i][0][1] == center_loc[1]:
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支的起始节点编号
                        node_x_1 = key_node_para[i][0][0]  # 第1支的起始节点x坐标
                        node_y_1 = key_node_para[i][0][1]  # 第1支的起始节点y坐标
                        node_z_1 = key_node_para[i][0][2]  # 第1支的起始节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_2 = first_node_tag + node_count + 1000  # 第2支的起始节点编号
                        node_x_2 = 2 * center_loc[0] - key_node_para[i][0][0]  # 第2支的起始节点x坐标
                        node_y_2 = key_node_para[i][0][1]  # 第2支的起始节点y坐标
                        node_z_2 = key_node_para[i][0][2]  # 第2支的起始节点z坐标
                        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
                        
                        node_count += 1
                        
                        key_nodes.append(node_count)  # 存储关键节点编号
                        anchor_nodes_range.append(node_count)  # 存储锚固区起始节点编号
                        if key_node_para[i][1] == 1:
                            beam_nodes_1.append(node_count)  # 存储横桥向横梁节点编号
                        
                    # 第1支+第3支（上下2个起始节点）
                    elif key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] != center_loc[1]:
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支的起始节点编号
                        node_x_1 = key_node_para[i][0][0]  # 第1支的起始节点x坐标
                        node_y_1 = key_node_para[i][0][1]  # 第1支的起始节点y坐标
                        node_z_1 = key_node_para[i][0][2]  # 第1支的起始节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_3 = first_node_tag + node_count + 2000  # 第3支的起始节点编号
                        node_x_3 = 2 * center_loc[0] - key_node_para[i][0][0]  # 第3支的起始节点x坐标
                        node_y_3 = 2 * center_loc[1] - key_node_para[i][0][1]  # 第3支的起始节点y坐标
                        node_z_3 = key_node_para[i][0][2]  # 第3支的起始节点z坐标
                        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
                        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}
                        
                        node_count += 1
                        
                        key_nodes.append(node_count)  # 存储关键节点编号
                        anchor_nodes_range.append(node_count)  # 存储锚固区起始节点编号
                        if key_node_para[i][2] == 1:
                            beam_nodes_2.append(node_count)  # 存储顺桥向横梁节点编号
                        
                    # 4支均有独立起始节点
                    else:
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支的起始节点编号
                        node_x_1 = key_node_para[i][0][0]  # 第1支的起始节点x坐标
                        node_y_1 = key_node_para[i][0][1]  # 第1支的起始节点y坐标
                        node_z_1 = key_node_para[i][0][2]  # 第1支的起始节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_2 = first_node_tag + node_count + 1000  # 第2支的起始节点编号
                        node_x_2 = 2 * center_loc[0] - key_node_para[i][0][0]  # 第2支的起始节点x坐标
                        node_y_2 = key_node_para[i][0][1]  # 第2支的起始节点y坐标
                        node_z_2 = key_node_para[i][0][2]  # 第2支的起始节点z坐标
                        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
                        
                        node_tag_3 = first_node_tag + node_count + 2000  # 第3支的起始节点编号
                        node_x_3 = 2 * center_loc[0] - key_node_para[i][0][0]  # 第3支的起始节点x坐标
                        node_y_3 = 2 * center_loc[1] - key_node_para[i][0][1]  # 第3支的起始节点y坐标
                        node_z_3 = key_node_para[i][0][2]  # 第3支的起始节点z坐标
                        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
                        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}
                        
                        node_tag_4 = first_node_tag + node_count + 3000  # 第4支的起始节点编号
                        node_x_4 = key_node_para[i][0][0]  # 第4支的起始节点x坐标
                        node_y_4 = 2 * center_loc[1] - key_node_para[i][0][1]  # 第4支的起始节点y坐标
                        node_z_4 = key_node_para[i][0][2]  # 第4支的起始节点z坐标
                        ops.node(node_tag_4, node_x_4, node_y_4, node_z_4)
                        skeleton['nodes'][node_tag_4] = {'crds':[node_x_4, node_y_4, node_z_4], 'mass':None}
                        
                        node_count += 1
                        
                        key_nodes.append(node_count)  # 存储关键节点编号
                        anchor_nodes_range.append(node_count)  # 存储锚固区起始节点编号
                        if key_node_para[i][1] == 1:
                            beam_nodes_1.append(node_count)  # 存储横桥向横梁节点编号
                        if key_node_para[i][2] == 1:
                            beam_nodes_2.append(node_count)  # 存储顺桥向横梁节点编号
                    
                    anchor_x_interval = anchor_x_interval[1:]  # 除去已经使用的锚固节点x坐标
                    anchor_y_interval = anchor_y_interval[1:]  # 除去已经使用的锚固节点y坐标
                    anchor_z_interval = anchor_z_interval[1:]  # 除去已经使用的锚固节点z坐标
                            
                
                # 1-2-2 当下一个锚固节点在下一个关键节点前时，建立该锚固节点
                elif anchor_z_interval[0] < key_node_para[i+1][0][2]:
                    
                    # 整个节段只有竖向1支
                    if (key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] == center_loc[1]) and \
                        (key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]):
                        
                        node_tag_1 = first_node_tag + node_count  # 锚固节点编号
                        node_x_1 = anchor_x_interval[0]  # 锚固节点x坐标
                        node_y_1 = anchor_y_interval[0]  # 锚固节点y坐标
                        node_z_1 = anchor_z_interval[0]  # 锚固节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        anchor_x_interval = anchor_x_interval[1:]  # 除去已经使用的锚固节点x坐标
                        anchor_y_interval = anchor_y_interval[1:]  # 除去已经使用的锚固节点y坐标
                        anchor_z_interval = anchor_z_interval[1:]  # 除去已经使用的锚固节点z坐标
                        
                        node_count += 1
                        
                    # 第1支+第2支（左右,3种组合情况）
                    elif ((key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] == center_loc[1]) and \
                            (key_node_para[i+1][0][0] != center_loc[0] and key_node_para[i+1][0][1] == center_loc[1])) \
                            or \
                            ((key_node_para[i][0][0] != center_loc[0] and key_node_para[i][0][1] == center_loc[1]) and \
                            ((key_node_para[i+1][0][0] != center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]) or \
                            (key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]))):
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支锚固节点编号
                        node_x_1 = anchor_x_interval[0]  # 第1支锚固节点x坐标
                        node_y_1 = anchor_y_interval[0]  # 第1支锚固节点y坐标
                        node_z_1 = anchor_z_interval[0]  # 第1支锚固节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_2 = first_node_tag + node_count + 1000  # 第2支锚固节点编号
                        node_x_2 = 2 * center_loc[0] - anchor_x_interval[0]  # 第2支锚固节点x坐标
                        node_y_2 = anchor_y_interval[0]  # 第2支锚固节点y坐标
                        node_z_2 = anchor_z_interval[0]  # 第2支锚固节点z坐标
                        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
                        
                        anchor_x_interval = anchor_x_interval[1:]  # 除去已经使用的锚固节点x坐标
                        anchor_y_interval = anchor_y_interval[1:]  # 除去已经使用的锚固节点y坐标
                        anchor_z_interval = anchor_z_interval[1:]  # 除去已经使用的锚固节点z坐标
                        
                        node_count += 1
                        
                    # 第1支+第3支（上下,3种组合情况）
                    elif ((key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] == center_loc[1]) and \
                            (key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] != center_loc[1])) \
                            or \
                            ((key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] != center_loc[1]) and \
                            ((key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] != center_loc[1]) or \
                            (key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]))):
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支锚固节点编号
                        node_x_1 = anchor_x_interval[0]  # 第1支锚固节点x坐标
                        node_y_1 = anchor_y_interval[0]  # 第1支锚固节点y坐标
                        node_z_1 = anchor_z_interval[0]  # 第1支锚固节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_3 = first_node_tag + node_count + 2000  # 第3支锚固节点编号
                        node_x_3 = 2 * center_loc[0] - anchor_x_interval[0]  # 第3支锚固节点x坐标
                        node_y_3 = 2 * center_loc[1] - anchor_y_interval[0]  # 第3支锚固节点y坐标
                        node_z_3 = anchor_z_interval[0]  # 第3支锚固节点z坐标
                        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
                        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}
                        
                        anchor_x_interval = anchor_x_interval[1:]  # 除去已经使用的锚固节点x坐标
                        anchor_y_interval = anchor_y_interval[1:]  # 除去已经使用的锚固节点y坐标
                        anchor_z_interval = anchor_z_interval[1:]  # 除去已经使用的锚固节点z坐标
                        
                        node_count += 1
                        
                    # 4支均存在
                    else:
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支锚固节点编号
                        node_x_1 = anchor_x_interval[0]  # 第1支锚固节点x坐标
                        node_y_1 = anchor_y_interval[0]  # 第1支锚固节点y坐标
                        node_z_1 = anchor_z_interval[0]  # 第1支锚固节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_2 = first_node_tag + node_count + 1000  # 第2支锚固节点编号
                        node_x_2 = 2 * center_loc[0] - anchor_x_interval[0]  # 第2支锚固节点x坐标
                        node_y_2 = anchor_y_interval[0]  # 第2支锚固节点y坐标
                        node_z_2 = anchor_z_interval[0]  # 第2支锚固节点z坐标
                        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
                        
                        node_tag_3 = first_node_tag + node_count + 2000  # 第3支锚固节点编号
                        node_x_3 = 2 * center_loc[0] - anchor_x_interval[0]  # 第3支锚固节点x坐标
                        node_y_3 = 2 * center_loc[1] - anchor_y_interval[0]  # 第3支锚固节点y坐标
                        node_z_3 = anchor_z_interval[0]  # 第3支锚固节点z坐标
                        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
                        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}
                        
                        node_tag_4 = first_node_tag + node_count + 3000  # 第4支锚固节点编号
                        node_x_4 = anchor_x_interval[0]  # 第4支锚固节点x坐标
                        node_y_4 = 2 * center_loc[1] - anchor_y_interval[0]  # 第4支锚固节点y坐标
                        node_z_4 = anchor_z_interval[0]  # 第4支锚固节点z坐标
                        ops.node(node_tag_4, node_x_4, node_y_4, node_z_4)
                        skeleton['nodes'][node_tag_4] = {'crds':[node_x_4, node_y_4, node_z_4], 'mass':None}
                        
                        anchor_x_interval = anchor_x_interval[1:]  # 除去已经使用的锚固节点x坐标
                        anchor_y_interval = anchor_y_interval[1:]  # 除去已经使用的锚固节点y坐标
                        anchor_z_interval = anchor_z_interval[1:]  # 除去已经使用的锚固节点z坐标
                        
                        node_count += 1
                        
                
                # 当下一个锚固节点在下一个关键点后或与下一个关键节点重合时，终止当前锚固节点的建立
                else:
                    break                
        
        
        # 1-3 当前节点为锚固区内的关键节点（非锚固区起始节点和终止节点）
        elif key_node_para[i][-1] == -1:
            
            # 下一个锚固节点与关键节点重合时
            if anchor_z_interval[0] == key_node_para[i][0][2]:
                
                anchor_num_rest = len(anchor_z_interval) - 1  # 尚未建模的锚固节点 + 1个关键点

            # 下一个锚固节点不与关键节点重合时
            else:

                anchor_num_rest = len(anchor_z_interval)  # 尚未建模的锚固节点 + 1个关键点
            
            for j in range(anchor_num_rest):

                # 起始节点建立
                if j == 0:
                    
                    # 第1支(1个共同起始节点)
                    if key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] == center_loc[1]:
                        
                        node_tag_1 = first_node_tag + node_count  # 共起始节点编号
                        node_x_1 = key_node_para[i][0][0]  # 共起始节点x坐标
                        node_y_1 = key_node_para[i][0][1]  # 共起始节点y坐标
                        node_z_1 = key_node_para[i][0][2] # 共起始节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        node_count += 1
                        key_nodes.append(node_count)  # 存储关键节点编号
                        no_anchor_nodes.append(node_count)  # 存储锚固区非锚点关键节点编号
                        
                    # 第1支+第2支（左右2个起始节点）
                    elif key_node_para[i][0][0] != center_loc[0] and key_node_para[i][0][1] == center_loc[1]:
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支的起始节点编号
                        node_x_1 = key_node_para[i][0][0]  # 第1支的起始节点x坐标
                        node_y_1 = key_node_para[i][0][1]  # 第1支的起始节点y坐标
                        node_z_1 = key_node_para[i][0][2]  # 第1支的起始节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_2 = first_node_tag + node_count + 1000  # 第2支的起始节点编号
                        node_x_2 = 2 * center_loc[0] - key_node_para[i][0][0]  # 第2支的起始节点x坐标
                        node_y_2 = key_node_para[i][0][1]  # 第2支的起始节点y坐标
                        node_z_2 = key_node_para[i][0][2]  # 第2支的起始节点z坐标
                        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
                        
                        node_count += 1
                        key_nodes.append(node_count)  # 存储关键节点编号
                        no_anchor_nodes.append(node_count)  # 存储锚固区非锚点关键节点编号
                        if key_node_para[i][1] == 1:
                            beam_nodes_1.append(node_count)  # 存储横桥向横梁节点编号
                        
                    # 第1支+第3支（上下2个起始节点）
                    elif key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] != center_loc[1]:
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支的起始节点编号
                        node_x_1 = key_node_para[i][0][0]  # 第1支的起始节点x坐标
                        node_y_1 = key_node_para[i][0][1]  # 第1支的起始节点y坐标
                        node_z_1 = key_node_para[i][0][2]  # 第1支的起始节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_3 = first_node_tag + node_count + 2000  # 第3支的起始节点编号
                        node_x_3 = 2 * center_loc[0] - key_node_para[i][0][0]  # 第3支的起始节点x坐标
                        node_y_3 = 2 * center_loc[1] - key_node_para[i][0][1]  # 第3支的起始节点y坐标
                        node_z_3 = key_node_para[i][0][2]  # 第3支的起始节点z坐标
                        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
                        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}
                        
                        node_count += 1
                        key_nodes.append(node_count)  # 存储关键节点编号
                        no_anchor_nodes.append(node_count)  # 存储锚固区非锚点关键节点编号
                        if key_node_para[i][2] == 1:
                            beam_nodes_2.append(node_count)  # 存储顺桥向横梁节点编号
                        
                    # 4支均有独立起始节点
                    else:
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支的起始节点编号
                        node_x_1 = key_node_para[i][0][0]  # 第1支的起始节点x坐标
                        node_y_1 = key_node_para[i][0][1]  # 第1支的起始节点y坐标
                        node_z_1 = key_node_para[i][0][2]  # 第1支的起始节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_2 = first_node_tag + node_count + 1000  # 第2支的起始节点编号
                        node_x_2 = 2 * center_loc[0] - key_node_para[i][0][0]  # 第2支的起始节点x坐标
                        node_y_2 = key_node_para[i][0][1]  # 第2支的起始节点y坐标
                        node_z_2 = key_node_para[i][0][2]  # 第2支的起始节点z坐标
                        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
                        
                        node_tag_3 = first_node_tag + node_count + 2000  # 第3支的起始节点编号
                        node_x_3 = 2 * center_loc[0] - key_node_para[i][0][0]  # 第3支的起始节点x坐标
                        node_y_3 = 2 * center_loc[1] - key_node_para[i][0][1]  # 第3支的起始节点y坐标
                        node_z_3 = key_node_para[i][0][2]  # 第3支的起始节点z坐标
                        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
                        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}
                        
                        node_tag_4 = first_node_tag + node_count + 3000  # 第4支的起始节点编号
                        node_x_4 = key_node_para[i][0][0]  # 第4支的起始节点x坐标
                        node_y_4 = 2 * center_loc[1] - key_node_para[i][0][1]  # 第4支的起始节点y坐标
                        node_z_4 = key_node_para[i][0][2]  # 第4支的起始节点z坐标
                        ops.node(node_tag_4, node_x_4, node_y_4, node_z_4)
                        skeleton['nodes'][node_tag_4] = {'crds':[node_x_4, node_y_4, node_z_4], 'mass':None}
                        
                        node_count += 1
                        key_nodes.append(node_count)  # 存储关键节点编号
                        no_anchor_nodes.append(node_count)  # 存储锚固区非锚点关键节点编号
                        if key_node_para[i][1] == 1:
                            beam_nodes_1.append(node_count)  # 存储横桥向横梁节点编号
                        if key_node_para[i][2] == 1:
                            beam_nodes_2.append(node_count)  # 存储顺桥向横梁节点编号
                                                     
                    # 下一个锚固节点与关键节点重合时
                    if anchor_z_interval[0] == key_node_para[i][0][2]:
                        
                        anchor_x_interval = anchor_x_interval[1:]  # 除去已经使用的锚固节点x坐标
                        anchor_y_interval = anchor_y_interval[1:]  # 除去已经使用的锚固节点y坐标
                        anchor_z_interval = anchor_z_interval[1:]  # 除去已经使用的锚固节点z坐标
                                                
                # 当下一个锚固节点在下一个关键节点前时，建立该锚固节点
                elif anchor_z_interval[0] < key_node_para[i+1][0][2]:
                    
                    # 整个节段只有竖向1支
                    if (key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] == center_loc[1]) and \
                        (key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]):
                        
                        node_tag_1 = first_node_tag + node_count  # 锚固节点编号
                        node_x_1 = anchor_x_interval[0]  # 锚固节点x坐标
                        node_y_1 = anchor_y_interval[0]  # 锚固节点y坐标
                        node_z_1 = anchor_z_interval[0]  # 锚固节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        anchor_x_interval = anchor_x_interval[1:]  # 除去已经使用的锚固节点x坐标
                        anchor_y_interval = anchor_y_interval[1:]  # 除去已经使用的锚固节点y坐标
                        anchor_z_interval = anchor_z_interval[1:]  # 除去已经使用的锚固节点z坐标
                        
                        node_count += 1
                        
                    # 第1支+第2支（左右,3种组合情况）
                    elif ((key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] == center_loc[1]) and \
                            (key_node_para[i+1][0][0] != center_loc[0] and key_node_para[i+1][0][1] == center_loc[1])) \
                            or \
                            ((key_node_para[i][0][0] != center_loc[0] and key_node_para[i][0][1] == center_loc[1]) and \
                            ((key_node_para[i+1][0][0] != center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]) or \
                            (key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]))):
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支锚固节点编号
                        node_x_1 = anchor_x_interval[0]  # 第1支锚固节点x坐标
                        node_y_1 = anchor_y_interval[0]  # 第1支锚固节点y坐标
                        node_z_1 = anchor_z_interval[0]  # 第1支锚固节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_2 = first_node_tag + node_count + 1000  # 第2支锚固节点编号
                        node_x_2 = 2 * center_loc[0] - anchor_x_interval[0]  # 第2支锚固节点x坐标
                        node_y_2 = anchor_y_interval[0]  # 第2支锚固节点y坐标
                        node_z_2 = anchor_z_interval[0]  # 第2支锚固节点z坐标
                        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
                        
                        anchor_x_interval = anchor_x_interval[1:]  # 除去已经使用的锚固节点x坐标
                        anchor_y_interval = anchor_y_interval[1:]  # 除去已经使用的锚固节点y坐标
                        anchor_z_interval = anchor_z_interval[1:]  # 除去已经使用的锚固节点z坐标
                        
                        node_count += 1
                        
                    # 第1支+第3支（上下,3种组合情况）
                    elif ((key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] == center_loc[1]) and \
                            (key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] != center_loc[1])) \
                            or \
                            ((key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] != center_loc[1]) and \
                            ((key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] != center_loc[1]) or \
                            (key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]))):
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支锚固节点编号
                        node_x_1 = anchor_x_interval[0]  # 第1支锚固节点x坐标
                        node_y_1 = anchor_y_interval[0]  # 第1支锚固节点y坐标
                        node_z_1 = anchor_z_interval[0]  # 第1支锚固节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_3 = first_node_tag + node_count + 2000  # 第3支锚固节点编号
                        node_x_3 = 2 * center_loc[0] - anchor_x_interval[0]  # 第3支锚固节点x坐标
                        node_y_3 = 2 * center_loc[1] - anchor_y_interval[0]  # 第3支锚固节点y坐标
                        node_z_3 = anchor_z_interval[0]  # 第3支锚固节点z坐标
                        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
                        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}
                        
                        anchor_x_interval = anchor_x_interval[1:]  # 除去已经使用的锚固节点x坐标
                        anchor_y_interval = anchor_y_interval[1:]  # 除去已经使用的锚固节点y坐标
                        anchor_z_interval = anchor_z_interval[1:]  # 除去已经使用的锚固节点z坐标
                        
                        node_count += 1
                        
                    # 4支均存在
                    else:
                        
                        node_tag_1 = first_node_tag + node_count  # 第1支锚固节点编号
                        node_x_1 = anchor_x_interval[0]  # 第1支锚固节点x坐标
                        node_y_1 = anchor_y_interval[0]  # 第1支锚固节点y坐标
                        node_z_1 = anchor_z_interval[0]  # 第1支锚固节点z坐标
                        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
                        
                        node_tag_2 = first_node_tag + node_count + 1000  # 第2支锚固节点编号
                        node_x_2 = 2 * center_loc[0] - anchor_x_interval[0]  # 第2支锚固节点x坐标
                        node_y_2 = anchor_y_interval[0]  # 第2支锚固节点y坐标
                        node_z_2 = anchor_z_interval[0]  # 第2支锚固节点z坐标
                        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
                        
                        node_tag_3 = first_node_tag + node_count + 2000  # 第3支锚固节点编号
                        node_x_3 = 2 * center_loc[0] - anchor_x_interval[0]  # 第3支锚固节点x坐标
                        node_y_3 = 2 * center_loc[1] - anchor_y_interval[0]  # 第3支锚固节点y坐标
                        node_z_3 = anchor_z_interval[0]  # 第3支锚固节点z坐标
                        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
                        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}
                        
                        node_tag_4 = first_node_tag + node_count + 3000  # 第4支锚固节点编号
                        node_x_4 = anchor_x_interval[0]  # 第4支锚固节点x坐标
                        node_y_4 = 2 * center_loc[1] - anchor_y_interval[0]  # 第4支锚固节点y坐标
                        node_z_4 = anchor_z_interval[0]  # 第4支锚固节点z坐标
                        ops.node(node_tag_4, node_x_4, node_y_4, node_z_4)
                        skeleton['nodes'][node_tag_4] = {'crds':[node_x_4, node_y_4, node_z_4], 'mass':None}
                        
                        anchor_x_interval = anchor_x_interval[1:]  # 除去已经使用的锚固节点x坐标
                        anchor_y_interval = anchor_y_interval[1:]  # 除去已经使用的锚固节点y坐标
                        anchor_z_interval = anchor_z_interval[1:]  # 除去已经使用的锚固节点z坐标
                        
                        node_count += 1
                
                # 当下一个锚固节点在下一个关键点后或与下一个关键节点重合时，终止当前锚固节点的建立
                else:
                    break
                    
                    
                                        
    # 1-4 补充最后一个节点（要结束啦）
    # 第1支(1个共同起始节点)
    if key_node_para[-1][0][0] == center_loc[0] and key_node_para[-1][0][1] == center_loc[1]:
        
        node_tag_1 = first_node_tag + node_count  # 共起始节点编号
        node_x_1 = key_node_para[-1][0][0]  # 共起始节点x坐标
        node_y_1 = key_node_para[-1][0][1]  # 共起始节点y坐标
        node_z_1 = key_node_para[-1][0][2]  # 共起始节点z坐标
        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}
        node_count += 1
        key_nodes.append(node_count)  # 存储关键节点编号

    # 第1支+第2支（左右2个起始节点）
    elif key_node_para[-1][0][0] != center_loc[0] and key_node_para[-1][0][1] == center_loc[1]:
        
        node_tag_1 = first_node_tag + node_count  # 第1支的终止节点编号
        node_x_1 = key_node_para[-1][0][0]  # 第1支的终止节点x坐标
        node_y_1 = key_node_para[-1][0][1]  # 第1支的终止节点y坐标
        node_z_1 = key_node_para[-1][0][2]  # 第1支的终止节点z坐标
        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}

        node_tag_2 = first_node_tag + node_count + 1000  # 第2支的终止节点编号
        node_x_2 = 2 * center_loc[0] - key_node_para[-1][0][0]  # 第2支的终止节点x坐标
        node_y_2 = key_node_para[-1][0][1]  # 第2支的终止节点y坐标
        node_z_2 = key_node_para[-1][0][2]  # 第2支的终止节点z坐标
        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}

        node_count += 1
        key_nodes.append(node_count)  # 存储关键节点编号
        if key_node_para[-1][1] == 1:
            beam_nodes_1.append(node_count)  # 存储横桥向横梁节点编号

    # 第1支+第3支（上下2个起始节点）
    elif key_node_para[-1][0][0] == center_loc[0] and key_node_para[-1][0][1] != center_loc[1]:
        
        node_tag_1 = first_node_tag + node_count  # 第1支的终止节点编号
        node_x_1 = key_node_para[-1][0][0]  # 第1支的终止节点x坐标
        node_y_1 = key_node_para[-1][0][1]  # 第1支的终止节点y坐标
        node_z_1 = key_node_para[-1][0][2]  # 第1支的终止节点z坐标
        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}

        node_tag_3 = first_node_tag + node_count + 2000  # 第3支的终止节点编号
        node_x_3 = 2 * center_loc[0] - key_node_para[-1][0][0]  # 第3支的终止节点x坐标
        node_y_3 = 2 * center_loc[1] - key_node_para[-1][0][1]  # 第3支的终止节点y坐标
        node_z_3 = key_node_para[-1][0][2]  # 第3支的起终止点z坐标
        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}

        node_count += 1
        key_nodes.append(node_count)  # 存储关键节点编号
        if key_node_para[-1][2] == 1:
            beam_nodes_2.append(node_count)  # 存储顺桥向横梁节点编号

    # 4支均有独立起始节点
    else:
        
        node_tag_1 = first_node_tag + node_count  # 第1支的终止节点编号
        node_x_1 = key_node_para[-1][0][0]  # 第1支的终止节点x坐标
        node_y_1 = key_node_para[-1][0][1]  # 第1支的终止节点y坐标
        node_z_1 = key_node_para[-1][0][2]  # 第1支的终止节点z坐标
        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}

        node_tag_2 = first_node_tag + node_count + 1000  # 第2支的终止节点编号
        node_x_2 = 2 * center_loc[0] - key_node_para[-1][0][0]  # 第2支的终止节点x坐标
        node_y_2 = key_node_para[-1][0][1]  # 第2支的终止节点y坐标
        node_z_2 = key_node_para[-1][0][2]  # 第2支的终止节点z坐标
        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}

        node_tag_3 = first_node_tag + node_count + 2000  # 第3支的终止节点编号
        node_x_3 = 2 * center_loc[0] - key_node_para[-1][0][0]  # 第3支的终止节点x坐标
        node_y_3 = 2 * center_loc[1] - key_node_para[-1][0][1]  # 第3支的终止节点y坐标
        node_z_3 = key_node_para[-1][0][2]  # 第3支的终止节点z坐标
        ops.node(node_tag_3, node_x_3, node_y_3, node_z_3)
        skeleton['nodes'][node_tag_3] = {'crds':[node_x_3, node_y_3, node_z_3], 'mass':None}

        node_tag_4 = first_node_tag + node_count + 3000  # 第4支的终止节点编号
        node_x_4 = key_node_para[-1][0][0]  # 第4支的终止节点x坐标
        node_y_4 = 2 * center_loc[1] - key_node_para[-1][0][1]  # 第4支的终止节点y坐标
        node_z_4 = key_node_para[-1][0][2]  # 第4支的终止节点z坐标
        ops.node(node_tag_4, node_x_4, node_y_4, node_z_4)
        skeleton['nodes'][node_tag_4] = {'crds':[node_x_4, node_y_4, node_z_4], 'mass':None}

        node_count += 1
        key_nodes.append(node_count)  # 存储关键节点编号
        if key_node_para[-1][1] == 1:
            beam_nodes_1.append(node_count)  # 存储横桥向横梁节点编号
        if key_node_para[-1][2] == 1:
            beam_nodes_2.append(node_count)  # 存储顺桥向横梁节点编号
            
    # 当最后一个节点同时也是锚固区终止节点时
    if key_node_para[-1][-1] == 0:
        
        anchor_nodes_range.append(node_count)  # 存储锚固区终止节点编号
        anchor_index = 0  # 退出锚固区
    
    
    
    # 自下而上逐段横梁定义横桥向横梁节点（实则为对称两根同时建立）
    if beam_div_num_1 > 1:
        zero_node_tag = 10011000 + tower_num * 100000  # 当前主塔的第1根横桥向横梁（未指定节点编号）
        beam_num_sum = 0  # 已建立节点的横桥向横梁数量（一侧）
        for i in range(len(key_node_para)):
            if key_node_para[i][1] == 1 and key_node_para[i][0][0] != center_loc[0]:
                node_y = key_node_para[i][0][1]  # 一根横桥向横梁上所有节点y坐标相同
                node_z = key_node_para[i][0][2]  # 一根横桥向横梁上所有节点z坐标相同
                
                x_interval = np.linspace(key_node_para[i][0][0], 2*center_loc[0]-key_node_para[i][0][0], beam_div_num_1+1)
                x_interval = np.round(x_interval, 2)
                
                if key_node_para[i][0][1] == center_loc[1]:
                    # 横梁在xz平面内，此时仅有一根
                    for j in range(beam_div_num_1):
                        if j != 0:
                            node_tag = zero_node_tag + beam_num_sum * 1000 + j
                            node_x = x_interval[j]
                            ops.node(node_tag, node_x, node_y, node_z)
                            skeleton['nodes'][node_tag] = {'crds':[node_x, node_y, node_z], 'mass':None}
                else:
                    # 横梁不在xz平面内，此时有两根
                    for j in range(beam_div_num_1):
                        if j != 0:
                            node_tag_1 = zero_node_tag + beam_num_sum * 1000 + j
                            node_x_1 = x_interval[j]
                            node_y_1 = node_y
                            ops.node(node_tag_1, node_x_1, node_y_1, node_z)
                            skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z], 'mass':None}
                            
                            node_tag_2 = zero_node_tag + beam_num_sum * 1000 + (beam_div_num_1 - 1) + j
                            node_x_2 = 2 * center_loc[0] - x_interval[j]
                            node_y_2 = 2 * center_loc[1] - node_y
                            ops.node(node_tag_2, node_x_2, node_y_2, node_z)
                            skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z], 'mass':None}
                        
                beam_num_sum += 1            
    
                
                
    # 自下而上逐段横梁定义顺桥向横梁节点（实则为对称两根同时建立）
    if beam_div_num_2 > 1:
        zero_node_tag = 10021000 + tower_num * 100000  # 当前主塔的第1根顺桥向横梁（未指定节点编号）
        beam_num_sum = 0  # 已建立节点的顺桥向横梁数量（一侧）
        for i in range(len(key_node_para)):
            if key_node_para[i][2] == 1 and key_node_para[i][0][1] != center_loc[1]:
                node_x = key_node_para[i][0][0]  # 一根顺桥向横梁上所有节点x坐标相同
                node_z = key_node_para[i][0][2]  # 一根顺桥向横梁上所有节点z坐标相同
                
                y_interval = np.linspace(key_node_para[i][0][1], 2*center_loc[1]-key_node_para[i][0][1], beam_div_num_2+1)
                y_interval = np.round(y_interval, 2)
                
                if key_node_para[i][0][0] == center_loc[0]:
                    # 横梁在xz平面内，此时仅有一根
                    for j in range(beam_div_num_2):
                        if j != 0:
                            node_tag = zero_node_tag + beam_num_sum * 1000 + j
                            node_y = y_interval[j]
                            ops.node(node_tag, node_x, node_y, node_z)
                            skeleton['nodes'][node_tag] = {'crds':[node_x, node_y, node_z], 'mass':None}
                else:
                    # 横梁不在xz平面内，此时有两根
                    for j in range(beam_div_num_1):
                        if j != 0:
                            node_tag_1 = zero_node_tag + beam_num_sum * 1000 + j
                            node_y_1 = y_interval[j]
                            node_x_1 = node_x
                            ops.node(node_tag_1, node_x_1, node_y_1, node_z)
                            skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z], 'mass':None}
                            
                            node_tag_2 = zero_node_tag + beam_num_sum * 1000 + (beam_div_num_1 - 1) + j
                            node_y_2 = 2 * center_loc[1] - y_interval[j]
                            node_x_2 = 2 * center_loc[0] - node_x
                            ops.node(node_tag_2, node_x_2, node_y_2, node_z)
                            skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z], 'mass':None}
                        
                beam_num_sum += 1
    
    
    
    

    # =========单元定义=========
    # 截面和坐标系转换方式（仅针对竖向构件）命名规则：
    # 采用六位整数命名，十万位表示主塔编号，万位表示构件类型（1为竖向构件，2为横桥向横梁，3为顺桥向横梁）
    # 千位表示竖向构件分支序号（横梁为0），其余三位表示顺序号
    # 横梁的坐标系转换方式命名有20001、20002、30001和30002四种（除十万位主塔编号以外）；
    # 单元命名规则：
    # 与节点命名规则相同
    c_sp = col_sec_para
    c_mp = col_mat_para
    
    sec_info_dict = {}  # 主塔截面信息字典（key-截面编号，value-[mp[i], sp[i]]）
    trans_info_dict = {}  # 主塔坐标转换信息字典
    if gravity_index:
        ops.pattern('Plain', load_pattern_tag, time_series_tag)  # 需要进行重力建模时，建立荷载pattern
    
    # 建立主塔竖向构件截面
    for i in range(len(key_node_para)-1):
        sec_tag_1 = 11001 + tower_num * 100000 + i
        ops.section('Elastic', sec_tag_1, c_mp[i][1], c_sp[i][0], c_sp[i][1], c_sp[i][2], c_mp[i][2], c_sp[i][3])
        skeleton['sections'][sec_tag_1] = {"secType": "elasticSection", "E_mod": c_mp[i][1], "area": c_sp[i][0], \
                                        "Iz": c_sp[i][1], "Iy": c_sp[i][2], "Jxx": c_sp[i][3], "G_mod": c_mp[i][2], \
                                        "rho" : c_mp[i][0]}
        if gravity_index:
            sec_info_dict[sec_tag_1] = [c_mp[i], c_sp[i]]

        sec_tag_2 = 12001 + tower_num * 100000 + i
        ops.section('Elastic', sec_tag_2, c_mp[i][1], c_sp[i][0], c_sp[i][1], c_sp[i][2], c_mp[i][2], c_sp[i][3])
        skeleton['sections'][sec_tag_2] = {"secType": "elasticSection", "E_mod": c_mp[i][1], "area": c_sp[i][0], \
                                        "Iz": c_sp[i][1], "Iy": c_sp[i][2], "Jxx": c_sp[i][3], "G_mod": c_mp[i][2], \
                                        "rho" : c_mp[i][0]}
        if gravity_index:
            sec_info_dict[sec_tag_2] = [c_mp[i], c_sp[i]]
            
        sec_tag_3 = 13001 + tower_num * 100000 + i
        ops.section('Elastic', sec_tag_3, c_mp[i][1], c_sp[i][0], c_sp[i][1], c_sp[i][2], c_mp[i][2], c_sp[i][3])
        skeleton['sections'][sec_tag_3] = {"secType": "elasticSection", "E_mod": c_mp[i][1], "area": c_sp[i][0], \
                                        "Iz": c_sp[i][1], "Iy": c_sp[i][2], "Jxx": c_sp[i][3], "G_mod": c_mp[i][2], \
                                        "rho" : c_mp[i][0]}
        if gravity_index:
            sec_info_dict[sec_tag_3] = [c_mp[i], c_sp[i]]

        sec_tag_4 = 14001 + tower_num * 100000 + i
        ops.section('Elastic', sec_tag_4, c_mp[i][1], c_sp[i][0], c_sp[i][1], c_sp[i][2], c_mp[i][2], c_sp[i][3])
        skeleton['sections'][sec_tag_4] = {"secType": "elasticSection", "E_mod": c_mp[i][1], "area": c_sp[i][0], \
                                        "Iz": c_sp[i][1], "Iy": c_sp[i][2], "Jxx": c_sp[i][3], "G_mod": c_mp[i][2], \
                                        "rho" : c_mp[i][0]}
        if gravity_index:
            sec_info_dict[sec_tag_4] = [c_mp[i], c_sp[i]]
        
    # 建立主塔竖向构件截面质量信息
    c_mass = []  # 主塔竖向构件截面质量信息
    for i in range(len(key_node_para)-1):
        c_mass.append(['-mass', c_mp[i][0]*c_sp[i][0], '-cMass'])  # 采用一致质量
    
    # 建立主塔竖向构件坐标系转换方式
    for i in range(len(key_node_para)-1):
        trans_tag_1 = 11001 + tower_num * 100000 + i
        vector_x = np.array([key_node_para[i+1][0][0] - key_node_para[i][0][0], \
                             key_node_para[i+1][0][1] - key_node_para[i][0][1], \
                             key_node_para[i+1][0][2] - key_node_para[i][0][2]])
        if vector_x[0] == 0 and vector_x[1] == 0:
            # 处理杆件为竖直布置的情况
            vector_z = np.array([1.0, 0.0, 0.0])  # (这里很奇怪，用np.array定义矩阵进去会报错；一定要浮点数，无语了)
        else:
            vector_temp = np.array([0, 0, 1])
            vector_z = np.cross(vector_x, vector_temp)
        ops.geomTransf('Linear', trans_tag_1, *vector_z)
        trans_info_dict[trans_tag_1] = vector_z
    
    for i in range(len(key_node_para)-1):
        trans_tag_2 = 12001 + tower_num * 100000 + i
        vector_x = np.array([key_node_para[i][0][0] - key_node_para[i+1][0][0], \
                             key_node_para[i+1][0][1] - key_node_para[i][0][1], \
                             key_node_para[i+1][0][2] - key_node_para[i][0][2]])
        if vector_x[0] == 0 and vector_x[1] == 0:
            # 处理杆件为竖直布置的情况
            vector_z = np.array([1.0, 0.0, 0.0])  # (这里很奇怪，用np.array定义矩阵进去会报错；一定要浮点数，无语了)
        else:
            vector_temp = np.array([0, 0, 1])
            vector_z = np.cross(vector_x, vector_temp)
        ops.geomTransf('Linear', trans_tag_2, *vector_z)
        trans_info_dict[trans_tag_2] = vector_z
        
    for i in range(len(key_node_para)-1):
        trans_tag_3 = 13001 + tower_num * 100000 + i
        vector_x = np.array([key_node_para[i][0][0] - key_node_para[i+1][0][0], \
                             key_node_para[i][0][1] - key_node_para[i+1][0][1], \
                             key_node_para[i+1][0][2] - key_node_para[i][0][2]])
        if vector_x[0] == 0 and vector_x[1] == 0:
            # 处理杆件为竖直布置的情况
            vector_z = np.array([-1.0, 0.0, 0.0])  # (这里很奇怪，用np.array定义矩阵进去会报错；一定要浮点数，无语了)
        else:
            vector_temp = np.array([0, 0, 1])
            vector_z = np.cross(vector_x, vector_temp)
        ops.geomTransf('Linear', trans_tag_3, *vector_z)
        trans_info_dict[trans_tag_3] = vector_z
        
    for i in range(len(key_node_para)-1):
        trans_tag_4 = 14001 + tower_num * 100000 + i
        vector_x = np.array([key_node_para[i+1][0][0] - key_node_para[i][0][0], \
                             key_node_para[i][0][1] - key_node_para[i+1][0][1], \
                             key_node_para[i+1][0][2] - key_node_para[i][0][2]])
        if vector_x[0] == 0 and vector_x[1] == 0:
            # 处理杆件为竖直布置的情况
            vector_z = np.array([-1.0, 0.0, 0.0])  # (这里很奇怪，用np.array定义矩阵进去会报错；一定要浮点数，无语了)
        else:
            vector_temp = np.array([0, 0, 1])
            vector_z = np.cross(vector_x, vector_temp)
        ops.geomTransf('Linear', trans_tag_4, *vector_z)
        trans_info_dict[trans_tag_4] = vector_z
    
        
    # 主塔横桥向横梁信息
    if beam_sec_para_1 != None:
        # 建立主塔横桥向横梁截面
        b_sp_1 = beam_sec_para_1
        b_mp_1 = beam_mat_para_1
        for i in range(len(beam_sec_para_1)):
            sec_tag = 20001 + tower_num * 100000 + i
            ops.section('Elastic', sec_tag, b_mp_1[i][1], b_sp_1[i][0], b_sp_1[i][1], \
                        b_sp_1[i][2], b_mp_1[i][2], b_sp_1[i][3])
            skeleton['sections'][sec_tag] = {"secType": "elasticSection", "E_mod": b_mp_1[i][1], "area": b_sp_1[i][0], \
                                            "Iz": b_sp_1[i][1], "Iy": b_sp_1[i][2], "Jxx": b_sp_1[i][3], "G_mod": b_mp_1[i][2], \
                                            "rho" : b_mp_1[i][0]}
            if gravity_index:
                sec_info_dict[sec_tag] = [b_mp_1[i], b_sp_1[i]]

        # 建立主塔横桥向横梁截面质量信息
        b_mass_1 = []  # 主塔横桥向横梁截面质量信息
        for i in range(len(beam_sec_para_1)):
            b_mass_1.append(['-mass', b_mp_1[i][0]*b_sp_1[i][0], '-cMass'])  # 采用一致质量

        # 建立主塔横桥向横梁坐标系转换方式
        ops.geomTransf('Linear', 20001 + tower_num * 100000, *[0,-1,0])
        trans_info_dict[20001 + tower_num * 100000] = [0,-1,0]
        ops.geomTransf('Linear', 20002 + tower_num * 100000, *[0,1,0])
        trans_info_dict[20002 + tower_num * 100000] = [0,1,0]
    
    
    # 主塔顺桥向横梁信息
    if beam_sec_para_2 != None:
        # 建立主塔顺桥向横梁截面
        b_sp_2 = beam_sec_para_2
        b_mp_2 = beam_mat_para_2
        for i in range(len(beam_sec_para_2)):
            sec_tag = 30001 + tower_num * 100000 + i
            ops.section('Elastic', sec_tag, b_mp_2[i][1], b_sp_2[i][0], b_sp_2[i][1], \
                        b_sp_2[i][2], b_mp_2[i][2], b_sp_2[i][3])
            skeleton['sections'][sec_tag] = {"secType": "elasticSection", "E_mod": b_mp_2[i][1], "area": b_sp_2[i][0], \
                                            "Iz": b_sp_2[i][1], "Iy": b_sp_2[i][2], "Jxx": b_sp_2[i][3], "G_mod": b_mp_2[i][2], \
                                            "rho" : b_mp_2[i][0]}
            if gravity_index:
                sec_info_dict[sec_tag] = [b_mp_2[i], b_sp_2[i]]

        # 建立主塔顺桥向横梁截面质量信息
        b_mass_2 = []  # 主塔顺桥向横梁截面质量信息
        for i in range(len(beam_sec_para_2)):
            b_mass_2.append(['-mass', b_mp_2[i][0]*b_sp_2[i][0], '-cMass'])  # 采用一致质量

        # 建立主塔顺桥向横梁坐标系转换方式
        ops.geomTransf('Linear', 30001 + tower_num * 100000, *[1,0,0])
        trans_info_dict[30001 + tower_num * 100000] = [1,0,0]
        ops.geomTransf('Linear', 30002 + tower_num * 100000, *[-1,0,0])
        trans_info_dict[30002 + tower_num * 100000] = [-1,0,0]
        
        
        
    
    # 主塔竖向构件单元建立
    # 按照4个分支的顺序分别建立
    first_ele_tag = 10001000 + tower_num * 100000  # 当前主塔第1分支竖向构件
    # 建立第1分支上的单元
    ele_count = 0  # 已建立的第1分支单元数量
    for i in range(len(key_node_para)-1):
        while ele_count < (key_nodes[i+1] - 1):
            ele_tag = first_ele_tag + ele_count + 1
            sec_tag = 11001 + tower_num * 100000 + i
            trans_tag = 11001 + tower_num * 100000 + i
            node_1_tag = ele_tag
            node_2_tag = ele_tag + 1
            ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *c_mass[i])
            skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
            ele_count += 1
            # 重力荷载建立
            if gravity_index:
                ele_len = element_len_cal(node_1_tag, node_2_tag)
                element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                          node_1_tag, node_2_tag)
    
    first_ele_tag = 10002000 + tower_num * 100000  # 当前主塔第2分支竖向构件
    # 建立第2分支上的单元
    for i in range(len(key_node_para)-1):
        sec_tag = 12001 + tower_num * 100000 + i
        trans_tag = 12001 + tower_num * 100000 + i
        if key_node_para[i][0][0] == center_loc[0] and key_node_para[i+1][0][0] == center_loc[0]:
            # 节段位于yz平面上，此时也仅有此时不存在第2分支
            pass
        else:
            # 节段存在第2分支时
            for j in range(key_nodes[i], key_nodes[i+1]):
                if j == key_nodes[i]:
                    # 起始单元建立
                    ele_tag = first_ele_tag + key_nodes[i]
                    if key_node_para[i][0][0] == center_loc[0]:
                        # 起始节点被第1分支合并时
                        node_1_tag = ele_tag - 1000
                    else:
                        node_1_tag = ele_tag
                    node_2_tag = ele_tag + 1

                    # 当节段仅有一个单元时（起始单元也是终止单元）
                    if key_nodes[i+1] - key_nodes[i] == 1:
                        if key_node_para[i+1][0][0] == center_loc[0]:
                            # 终止节点被第1分支合并时
                            node_2_tag = ele_tag - 1000 + 1

                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *c_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}

                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
                    
                elif j == key_nodes[i+1] - 1:
                    # 终止单元建立
                    ele_tag = first_ele_tag + key_nodes[i+1] - 1
                    if key_node_para[i+1][0][0] == center_loc[0]:
                        # 终止节点被第1分支合并时
                        node_2_tag = ele_tag - 1000 + 1
                    else:
                        node_2_tag = ele_tag + 1
                    node_1_tag = ele_tag
                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *c_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
                    
                else:
                    # 中间单元建立
                    ele_tag = first_ele_tag + j
                    node_1_tag = ele_tag
                    node_2_tag = ele_tag + 1
                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *c_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
    
    
    first_ele_tag = 10003000 + tower_num * 100000  # 当前主塔第3分支竖向构件
    # 建立第3分支上的单元
    for i in range(len(key_node_para)-1):
        sec_tag = 13001 + tower_num * 100000 + i
        trans_tag = 13001 + tower_num * 100000 + i
        if key_node_para[i][0][1] == center_loc[1] and key_node_para[i+1][0][1] == center_loc[1]:
            # 节段位于xz平面上，此时也仅有此时不存在第3分支
            pass
        else:
            # 节段存在第3分支时
            for j in range(key_nodes[i], key_nodes[i+1]):
                if j == key_nodes[i]:
                    # 起始单元建立
                    ele_tag = first_ele_tag + key_nodes[i]
                    if key_node_para[i][0][0] == center_loc[0] and key_node_para[i][0][1] == center_loc[1]:
                        # 起始节点被第1分支合并时
                        node_1_tag = ele_tag - 2000
                    elif key_node_para[i][0][0] != center_loc[0] and key_node_para[i][0][1] == center_loc[1]:
                        # 起始节点被第2分支合并时
                        node_1_tag = ele_tag - 1000
                    else:
                        node_1_tag = ele_tag
                    node_2_tag = ele_tag + 1

                    # 当节段仅有一个单元时（起始单元也是终止单元）
                    if key_nodes[i+1] - key_nodes[i] == 1:
                        if key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]:
                            # 终止节点被第1分支合并时
                            node_2_tag = ele_tag - 2000 + 1
                        elif key_node_para[i+1][0][0] != center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]:
                            # 终止节点被第2分支合并时
                            node_2_tag = ele_tag - 1000 + 1

                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *c_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}

                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
                    
                elif j == key_nodes[i+1] - 1:
                    # 终止单元建立
                    ele_tag = first_ele_tag + key_nodes[i+1] - 1
                    if key_node_para[i+1][0][0] == center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]:
                        # 终止节点被第1分支合并时
                        node_2_tag = ele_tag - 2000 + 1
                    elif key_node_para[i+1][0][0] != center_loc[0] and key_node_para[i+1][0][1] == center_loc[1]:
                        # 终止节点被第2分支合并时
                        node_2_tag = ele_tag - 1000 + 1
                    else:
                        node_2_tag = ele_tag + 1
                    node_1_tag = ele_tag
                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *c_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
                    
                else:
                    # 中间单元建立
                    ele_tag = first_ele_tag + j
                    node_1_tag = ele_tag
                    node_2_tag = ele_tag + 1
                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *c_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
                
                    
    first_ele_tag = 10004000 + tower_num * 100000  # 当前主塔第4分支竖向构件
    # 建立第4分支上的单元
    for i in range(len(key_node_para)-1):
        sec_tag = 14001 + tower_num * 100000 + i
        trans_tag = 14001 + tower_num * 100000 + i
        if (key_node_para[i][0][1] == center_loc[1] and key_node_para[i+1][0][1] == center_loc[1]) or \
            (key_node_para[i][0][0] == center_loc[0] and key_node_para[i+1][0][0] == center_loc[0]):
            # 节段位于xz平面或yz平面上，此时也仅有此时不存在第4分支
            pass
        else:
            # 节段存在第4分支时
            for j in range(key_nodes[i], key_nodes[i+1]):
                if j == key_nodes[i]:
                    # 起始单元建立
                    ele_tag = first_ele_tag + key_nodes[i]
                    if key_node_para[i][0][1] == center_loc[1]:
                        # 起始节点被第1分支合并时
                        node_1_tag = ele_tag - 3000
                    elif key_node_para[i][0][0] == center_loc[0]:
                        # 起始节点被第3分支合并时
                        node_1_tag = ele_tag - 1000
                    else:
                        node_1_tag = ele_tag
                    node_2_tag = ele_tag + 1

                    # 当节段仅有一个单元时（起始单元也是终止单元）
                    if key_nodes[i+1] - key_nodes[i] == 1:
                        if key_node_para[i+1][0][1] == center_loc[1]:
                            # 终止节点被第1分支合并时
                            node_2_tag = ele_tag - 3000 + 1
                        elif key_node_para[i+1][0][0] == center_loc[0]:
                            # 终止节点被第3分支合并时
                            node_2_tag = ele_tag - 1000 + 1

                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *c_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}

                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
                    
                elif j == key_nodes[i+1] - 1:
                    # 终止单元建立
                    ele_tag = first_ele_tag + key_nodes[i+1] - 1
                    if key_node_para[i+1][0][1] == center_loc[1]:
                        # 终止节点被第1分支合并时
                        node_2_tag = ele_tag - 3000 + 1
                    elif key_node_para[i+1][0][0] == center_loc[0]:
                        # 终止节点被第3分支合并时
                        node_2_tag = ele_tag - 1000 + 1
                    else:
                        node_2_tag = ele_tag + 1
                    node_1_tag = ele_tag
                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *c_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
                    
                else:
                    # 中间单元建立
                    ele_tag = first_ele_tag + j
                    node_1_tag = ele_tag
                    node_2_tag = ele_tag + 1
                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *c_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
                    
            
    
    # 主塔横桥向横梁单元建立
    if beam_sec_para_1 != None:
        beam_sec_para = beam_sec_para_1
        beam_div_num = beam_div_num_1
        beam_nodes = beam_nodes_1
        b_mass = b_mass_1
        
        first_ele_tag = 10011001 + tower_num * 100000  # 当前主塔的第1横桥向横梁的第1个单元
        for i in range(len(beam_sec_para)):
            sec_tag = 20001 + tower_num * 100000 + i
            if beam_div_num > 1:
                # 当横桥向横梁划分多于1个单元时
                trans_tag = 20001 + tower_num * 100000
                for j in range(beam_div_num):
                    ele_tag = first_ele_tag + 1000 * i + j
                    if j == 0:
                        # 起始单元
                        node_1_tag = 10001000 + tower_num * 100000 + beam_nodes[i]
                        node_2_tag = ele_tag
                    elif j == beam_div_num - 1:
                        # 终止单元
                        node_1_tag = ele_tag - 1
                        node_2_tag = 10002000 + tower_num * 100000 + beam_nodes[i]
                    else:
                        node_1_tag = ele_tag - 1
                        node_2_tag = ele_tag
                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *b_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
                    
                index_node_tag = 10001000 + tower_num * 100000 + beam_nodes[i]  # 判断横桥向横梁是否有对称另一根的参考节点
                index_loc = ops.nodeCoord(index_node_tag)
                if index_loc[1] != center_loc[1]:
                    trans_tag = 20002 + tower_num * 100000
                    for j in range(beam_div_num):
                        ele_tag = first_ele_tag + 1000 * i + j + beam_div_num
                        if j == 0:
                            # 起始单元
                            node_1_tag = 10003000 + tower_num * 100000 + beam_nodes[i]
                            node_2_tag = ele_tag - 1
                        elif j == beam_div_num - 1:
                            # 终止单元
                            node_1_tag = ele_tag - 2
                            node_2_tag = 10004000 + tower_num * 100000 + beam_nodes[i]
                        else:
                            node_1_tag = ele_tag - 2
                            node_2_tag = ele_tag - 1
                        ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *b_mass[i])
                        skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                            "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                        # 重力荷载建立
                        if gravity_index:
                            ele_len = element_len_cal(node_1_tag, node_2_tag)
                            element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                    node_1_tag, node_2_tag)
                
            else:
                # 当横桥向横梁划分少于1个单元时
                ele_tag = first_ele_tag + 1000 * i
                trans_tag = 20001 + tower_num * 100000
                node_1_tag = 10001000 + tower_num * 100000 + beam_nodes[i]
                node_2_tag = 10002000 + tower_num * 100000 + beam_nodes[i]
                ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *b_mass[i])
                skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                    "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                # 重力荷载建立
                if gravity_index:
                    ele_len = element_len_cal(node_1_tag, node_2_tag)
                    element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                            node_1_tag, node_2_tag)
                
                index_node_tag = 10001000 + tower_num * 100000 + beam_nodes[i]  # 判断横桥向横梁是否有对称另一根的参考节点
                index_loc = ops.nodeCoord(index_node_tag)
                if index_loc[1] != center_loc[1]:
                    ele_tag = first_ele_tag + 1000 * i + 1
                    trans_tag = 120002
                    node_1_tag = 10003000 + tower_num * 100000 + beam_nodes[i]
                    node_2_tag = 10004000 + tower_num * 100000 + beam_nodes[i]
                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *b_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
                    
                    
    
    # 主塔顺桥向横梁单元建立
    if beam_sec_para_2 != None:

        beam_sec_para = beam_sec_para_2
        beam_div_num = beam_div_num_2
        beam_nodes = beam_nodes_2
        b_mass = b_mass_2
        
        first_ele_tag = 10021001 + tower_num * 100000  # 当前主塔的第1顺桥向横梁的第1个单元
        for i in range(len(beam_sec_para)):
            sec_tag = 30001 + tower_num * 100000 + i
            if beam_div_num > 1:
                # 当顺桥向横梁划分多于1个单元时
                index_node_tag = 10001000 + tower_num * 100000 + beam_nodes[i]  # 判断顺桥向横梁是否有对称另一根的参考节点
                index_loc = ops.nodeCoord(index_node_tag)
                if index_loc[0] != center_loc[0]:
                    # 有对称的另一根顺桥向横梁
                    trans_tag = 30001 + tower_num * 100000
                    for j in range(beam_div_num):
                        ele_tag = first_ele_tag + 1000 * i + j
                        if j == 0:
                            # 起始单元
                            node_1_tag = 10001000 + tower_num * 100000 + beam_nodes[i]
                            node_2_tag = ele_tag
                        elif j == beam_div_num - 1:
                            # 终止单元
                            node_1_tag = ele_tag - 1
                            node_2_tag = 10004000 + tower_num * 100000 + beam_nodes[i]
                        else:
                            node_1_tag = ele_tag - 1
                            node_2_tag = ele_tag
                        ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *b_mass[i])
                        skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                            "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                        # 重力荷载建立
                        if gravity_index:
                            ele_len = element_len_cal(node_1_tag, node_2_tag)
                            element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                    node_1_tag, node_2_tag)
                    
                    trans_tag = 30002 + tower_num * 100000
                    for j in range(beam_div_num):
                        ele_tag = first_ele_tag + 1000 * i + j + beam_div_num
                        if j == 0:
                            # 起始单元
                            node_1_tag = 10003000 + tower_num * 100000 + beam_nodes[i]
                            node_2_tag = ele_tag - 1
                        elif j == beam_div_num - 1:
                            # 终止单元
                            node_1_tag = ele_tag - 2
                            node_2_tag = 10002000 + tower_num * 100000 + beam_nodes[i]
                        else:
                            node_1_tag = ele_tag - 2
                            node_2_tag = ele_tag - 1
                        ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *b_mass[i])
                        skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                            "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                        # 重力荷载建立
                        if gravity_index:
                            ele_len = element_len_cal(node_1_tag, node_2_tag)
                            element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                    node_1_tag, node_2_tag)
                        
                else:
                    # 只有一根顺桥向横梁
                    trans_tag = 30001 + tower_num * 100000
                    for j in range(beam_div_num):
                        ele_tag = first_ele_tag + 1000 * i + j
                        if j == 0:
                            # 起始单元
                            node_1_tag = 10001000 + tower_num * 100000 + beam_nodes[i]
                            node_2_tag = ele_tag
                        elif j == beam_div_num - 1:
                            # 终止单元
                            node_1_tag = ele_tag - 1
                            node_2_tag = 10003000 + tower_num * 100000 + beam_nodes[i]
                        else:
                            node_1_tag = ele_tag - 1
                            node_2_tag = ele_tag
                        ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *b_mass[i])
                        skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                            "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                        # 重力荷载建立
                        if gravity_index:
                            ele_len = element_len_cal(node_1_tag, node_2_tag)
                            element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                    node_1_tag, node_2_tag)
                    
                
                
            else:
                # 当顺桥向横梁划分少于1个单元时
                index_node_tag = 10001000 + tower_num * 100000 + beam_nodes[i]  # 判断横桥向横梁是否有对称另一根的参考节点
                index_loc = ops.nodeCoord(index_node_tag)
                if index_loc[1] != center_loc[0]:
                    # 有对称的另一根顺桥向横梁
                    ele_tag = first_ele_tag + 1000 * i + 1
                    trans_tag = 30002 + tower_num * 100000
                    node_1_tag = 10003000 + tower_num * 100000 + beam_nodes[i]
                    node_2_tag = 10002000 + tower_num * 100000 + beam_nodes[i]
                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *b_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
                    
                    ele_tag = first_ele_tag + 1000 * i
                    trans_tag = 30001 + tower_num * 100000
                    node_1_tag = 10001000 + tower_num * 100000 + beam_nodes[i]
                    node_2_tag = 10004000 + tower_num * 100000 + beam_nodes[i]
                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *b_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
                    
                else:
                    # 只有一根顺桥向横梁
                    ele_tag = first_ele_tag + 1000 * i
                    trans_tag = 30001 + tower_num * 100000
                    node_1_tag = 10001000 + tower_num * 100000 + beam_nodes[i]
                    node_2_tag = 10003000 + tower_num * 100000 + beam_nodes[i]
                    ops.element('elasticBeamColumn', ele_tag, node_1_tag, node_2_tag, sec_tag, trans_tag, *b_mass[i])
                    skeleton['elements'][ele_tag] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag, node_2_tag], \
                                                        "vecxz": list(trans_info_dict[trans_tag]), "secTag": sec_tag, "cMass": "-cMass"}
                    # 重力荷载建立
                    if gravity_index:
                        ele_len = element_len_cal(node_1_tag, node_2_tag)
                        element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag, node_2_tag)
    
    return key_nodes, beam_nodes_1, beam_nodes_2, anchor_nodes_range, no_anchor_nodes




# 斜拉索建模
def cables_modelling(anchor_nodes_range_list, no_anchor_nodes_list, tower_center_loc_list, \
                        girder_div_num_list, insert_node_num, cable_num, \
                        cable_area_list_1, girder_G_list, \
                        cable_plane_num, invert_index, \
                        skeleton, \
                        gravity_index=0, load_pattern_tag=-1, time_series_tag=-1, \
                        cable_f_return_index=0, \
                        cable_area_list_2=None, cable_f_list_1=None, cable_f_list_2=None):
    
    # =========斜拉索有限元建模=========
    # 思路：斜拉索按照单个truss单元+弹性模量折减的方式进行建模
    # 斜拉索的截面积由输入的数组确定，其估计环节不在本函数内进行
    # 对于三索面斜拉桥，留有第二组斜拉索截面积的接口以适应中索面和边索面拉索截面积不一致的情况
    #
    # 数据格式：
    # anchor_nodes_range_list = 各个主塔的锚固区间起始与终止节点编号数组 = 
    #                           [[主塔1锚固区起始节点编号， 主塔1锚固区终止节点编号], [主塔2...], ...]
    #                           （需要注意首尾两个节点都不是锚固节点，需要跳过）
    # no_anchor_nodes_list = 各个主塔的锚固区间非锚固节点编号数组 = [[主塔1...], [主塔2...], ...]
    # tower_center_loc_list = 各个主塔的定位中心点坐标 = [[主塔1...], [主塔2...], ...]
    # girder_div_num_list = 加劲梁各区段划分的单元数量（未考虑加密节点）=
    #                      [边跨1密索区单元数, 边跨2密索区单元数, 边跨1边端无索区单元数, 边跨2边端无索区单元数, 
    #                       主塔无索区单元数, 跨中无索区单元数]
    # insert_node_num = 加劲梁加密点数量
    # cable_num = 单侧拉索根数
    # 
    # cable_area_list_1 = 斜拉索截面积数组1，适用于仅有一种索排布形式的情形 = 
    #                     [[边跨1斜拉索], [主跨1斜拉索1], [主跨1斜拉索2], ... , [边跨2斜拉索]]（按锚固点从塔上部到塔下部的顺序）
    # 
    # girder_G_list = 斜拉索下梁端自重
    # 
    # cable_plane_num = 斜拉索面数
    # invert_index = 斜拉索“倒转布置”指标（取值为0或1，1表示倒转，0则不倒转） = [[主塔1指标], [主塔2指标], ...]
    #                （“倒转”指长索改为靠塔底布置，短索反之，整体上与常规布置相比恰为倒转情形）
    # 
    # skeleton = 桥梁骨架信息
    #
    # load_pattern_tag = 荷载pattern编号
    # time_series_tag = 时间序列序号
    # gravity_index = 拉索建模是否同时进行重力荷载建模
    # 
    # cable_area_list_2 = 斜拉索截面积数组2，用于补充三索面条件下具有两种索排布形式的情形中的中索面布置 = （参考数组1）
    # 
    # cable_f_list_1 = 斜拉索索力数组1，适用于仅有一种索排布形式的情形 =
    #                     [[边跨1斜拉索], [主跨1斜拉索1], [主跨1斜拉索2], ... , [边跨2斜拉索]]（按锚固点从塔上部到塔下部的顺序）
    # cable_f_list_2 = 斜拉索索力数组2，用于补充三索面条件下具有两种索排布形式的情形中的中索面布置 = （参考数组1）
    # 
    # （以上，“边跨1”指位于y轴负半轴的边跨，“边跨2”为位于y轴正半轴的边跨）
    

    origin_cable_f_list = [[], []]  # 初始索力数组（按重力分配），对应f1和f2
    
    tower_num = len(anchor_nodes_range_list)  # 主塔数量
    elastic_modulus = 2.1e5  # 钢索弹性模量（MPa）
    work_stress = 1800000 * 0.4  # 钢索工作应力（kPa）
    cable_density = 7850 * 9.8 / 1000  # 钢索密度（kN/m^3）
    
    anchor_densed_num_1 = girder_div_num_list[0]  # 边跨1密索区单元数
    anchor_densed_num_2 = girder_div_num_list[1]  # 边跨2密索区单元数
    no_anchor_num_side_1 = girder_div_num_list[2]  # 边跨1边端无索区单元数
    no_anchor_num_side_2 = girder_div_num_list[3]  # 边跨2边端无索区单元数
    no_anchor_num_tower = girder_div_num_list[4]  # 主塔无索区单元数
    no_anchor_num_middle = girder_div_num_list[5]  # 跨中无索区单元数
    
    # 处理主塔锚固点起止节点编号（掐头去尾）
    for i in range(len(anchor_nodes_range_list)):
        anchor_nodes_range_list[i][0] = anchor_nodes_range_list[i][0] + 1
        anchor_nodes_range_list[i][1] = anchor_nodes_range_list[i][1] - 1
    
    # 根据主塔拉索“倒转”情况处理主塔锚固区间起始与终止节点编号
    for i in range(tower_num):
        if invert_index[i] == 0:
            temp_start_node = anchor_nodes_range_list[i][-1]
            anchor_nodes_range_list[i][-1] = anchor_nodes_range_list[i][0]
            anchor_nodes_range_list[i][0] = temp_start_node

    # 根据主塔拉索“倒转”情况处理斜拉索下梁端自重
    for i in range(tower_num):
        if invert_index[i] == 0:
            girder_G_list[2*i+1] = list(reversed(girder_G_list[2*i+1]))
        else:
            girder_G_list[2*i] = list(reversed(girder_G_list[2*i]))

    # =========单元定义=========
    # 命名规则：
    # 拉索节点采用八位整数命名，千万位为3表示拉索结构
    # 百万位和十万位表示所在纵曲线序号（按鱼骨梁形状，自x轴负轴至正轴方向依次为02，01，03）
    # 其余五位为节点序号
    
    sec_info_dict = {}  # 斜拉索截面信息字典（key-截面编号，value-[mp[i], sp[i]]）
    if gravity_index:
        ops.pattern('Plain', load_pattern_tag, time_series_tag)  # 需要进行重力建模时，建立荷载pattern

    # 中索面建立
    if cable_plane_num == 1 or cable_plane_num == 3:
        
        cable_count = 0  # 累计建立的拉索单元数量
        ele_tag_0 = 30100000
        para_tag_0 = 10000
        
        # 中索面的拉索截面积数据视索面数采用
        if cable_plane_num == 3 and cable_area_list_2 != None:
            cable_area_list = cable_area_list_2
        else:
            cable_area_list = cable_area_list_1

        # 中索面的拉索索力数据视索面数采用
        if cable_f_list_1 == None and cable_f_list_2 == None:
            cable_f_list = []
        elif cable_plane_num == 3 and cable_f_list_2 != None:
            cable_f_list = cable_f_list_2
        else:
            cable_f_list = cable_f_list_1

        # 按索面顺序建立拉索单元
        for j in range(tower_num*2):
            tower_index = j // 2  # 当前主塔序号

            # 1-根据主塔序号确定主塔锚固节点编号序列
            tower_start_node = anchor_nodes_range_list[tower_index][0]
            tower_end_node = anchor_nodes_range_list[tower_index][1]
            tower_node_list = np.linspace(tower_start_node, tower_end_node, \
                                          int(abs(tower_end_node - tower_start_node) + 1))  # 包含非锚固关键节点
            
            girder_start_node_0 = no_anchor_num_side_1 * (insert_node_num + 1) + 1  # 最初的加劲梁锚固节点编号
            
            # 2-根据索面位置确定加劲梁锚固节点编号序列
            # y轴负半轴边跨
            if j == 0:
                girder_start_node = girder_start_node_0
                girder_end_node = girder_start_node + (cable_num - 1) * (insert_node_num + 1)
                girder_node_list = np.linspace(girder_start_node, girder_end_node, \
                                            int(girder_end_node - girder_start_node + 1))  # 包含插入节点
            # 靠主塔y轴正半区方向的索面
            elif j % 2 == 1:
                girder_start_node = girder_end_node + 2 * no_anchor_num_tower * (insert_node_num + 1)
                girder_end_node = girder_start_node + (cable_num - 1) * (insert_node_num + 1)
                girder_node_list = np.linspace(girder_end_node, girder_start_node, \
                                               int(girder_end_node - girder_start_node + 1))  # 包含插入节点
            # 靠主塔y轴负半区方向的索面
            else:
                girder_start_node = girder_end_node + no_anchor_num_middle * (insert_node_num + 1)
                girder_end_node = girder_start_node + (cable_num - 1) * (insert_node_num + 1)
                girder_node_list = np.linspace(girder_start_node, girder_end_node, \
                                               int(girder_end_node - girder_start_node + 1))  # 包含插入节点
            
            if cable_f_return_index:
                temp_origin_f_list = []

            # 3-拉索单元建立-1-靠主塔y轴正半区方向的索面
            if j % 2 == 1:
                # 逐根拉索建立单元
                for i in range(cable_num):
                    cable_count += 1
                    girder_node = 20100000 + int(girder_node_list[i*(insert_node_num+1)])  # 拉索加劲梁锚固节点
                    
                    while tower_node_list[0] in no_anchor_nodes_list[tower_index]:
                        # 排除主塔锚固区非锚固节点
                        tower_node_list = tower_node_list[1:]
                        
                    tower_node = 10101000 + tower_index * 100000 + int(tower_node_list[0])  # 拉索主塔锚固节点
                    tower_node_list = tower_node_list[1:]
                    
                    if ops.nodeCoord(tower_node)[1] != tower_center_loc_list[tower_index][1]:
                        # 当拉索需要锚固在第3分支时
                        tower_node = tower_node + 2000
                    else:
                        pass
                    
                    # 计算拉索夹角余弦乘索长
                    base = np.sqrt((ops.nodeCoord(tower_node)[0] - ops.nodeCoord(girder_node)[0]) ** 2 + \
                                (ops.nodeCoord(tower_node)[1] - ops.nodeCoord(girder_node)[1]) ** 2)
                    # 计算拉索长度
                    ele_len = element_len_cal(tower_node, girder_node)
                    # 计算拉索夹角正弦
                    cable_sin = abs(ops.nodeCoord(tower_node)[2] - ops.nodeCoord(girder_node)[2]) / ele_len
                    # 计算折减后的钢索弹性模量
                    ernst_moduls = elastic_modulus / (1 + elastic_modulus * 1000 * \
                                                    (cable_density * base) ** 2 / (12 * work_stress ** 3))
                    ernst_moduls = ernst_moduls * 1e6  # 将单位转换为Pa
                    
                    # 建立材料和截面信息
                    para_tag_1_1 = para_tag_0 + cable_count
                    para_tag_1_2 = para_tag_0 + cable_count + 5000

                    cable_A = cable_area_list[j][i]
                    if cable_f_list != []:
                        cable_f = cable_f_list[j][i]
                    elif cable_plane_num == 1:
                        cable_f = girder_G_list[j][i] / cable_sin
                        if cable_f_return_index:
                            temp_origin_f_list.append(cable_f)
                    else:
                        cable_f = girder_G_list[j][i] / 2 / cable_sin
                        if cable_f_return_index:
                            temp_origin_f_list.append(cable_f)
                    cable_E = ernst_moduls

                    # ops.uniaxialMaterial('Elastic', para_tag_1_1, cable_E, 0.0, 1)
                    ops.uniaxialMaterial('Elastic', para_tag_1_1, cable_E)


                    cable_stress = cable_f / cable_A
                    cable_strain = cable_stress / cable_E

                    ops.uniaxialMaterial('InitStrainMaterial', para_tag_1_2, para_tag_1_1, cable_strain)

                    
                    cable_mass = ['-rho', cable_density * cable_A / 9.8 * 1000, '-cMass', 1]
                    cable_damp = ['-doRayleigh', 1]

                    # skeleton['materials'][para_tag_1_1] = {"matType": "Elastic", "E_mod": cable_E, \
                    #                                        "nu":None, "rho": cable_density * cable_A / 9.8 * 1000}
                    skeleton['sections'][para_tag_1_2] = {"secType": "elasticSection", "E_mod": cable_E, "area": cable_A, \
                                        "Iz": 0, "Iy": 0, "Jxx": 0, "G_mod": 0, \
                                        "rho" : cable_density * cable_A / 9.8 * 1000}
                    
                    # 建立单元
                    ele_tag = ele_tag_0 + cable_count
#                     ops.element('Truss', ele_tag, tower_node, girder_node, cable_A, \
#                                    para_tag_1_2, *cable_mass, *cable_damp)
                    ops.element('corotTruss', ele_tag, tower_node, girder_node, cable_A, \
                                   para_tag_1_2, *cable_mass, *cable_damp)
                    skeleton['elements'][ele_tag] = {"eleType": "Truss", "eleNodesTags": [tower_node, girder_node], \
                                                        "secTag": para_tag_1_2, \
                                                        "rho": cable_density * cable_A / 9.8 * 1000, "cMass": "-cMass"}
                    
                    # 重力荷载建立
                    if gravity_index:
                        sec_info_dict[para_tag_1_2] = [[cable_density], [cable_A]]
                        element_G_load_create(para_tag_1_2, ele_len, sec_info_dict, \
                                                  tower_node, girder_node)
                
                if cable_f_return_index:
                    origin_cable_f_list[0].append(temp_origin_f_list)
            
            # 3-拉索单元建立-2-靠主塔y轴负半区方向的索面
            else:
                # 逐根拉索建立单元
                for i in range(cable_num):
                    cable_count += 1
                    girder_node = 20100000 + int(girder_node_list[i*(insert_node_num+1)])  # 拉索加劲梁锚固节点
                    while tower_node_list[0] in no_anchor_nodes_list[tower_index]:
                        # 排除主塔锚固区非锚固节点
                        tower_node_list = tower_node_list[1:]
                    
                    tower_node = 10101000 + tower_index * 100000 + int(tower_node_list[0])  # 拉索主塔锚固节点
                    tower_node_list = tower_node_list[1:]
                    
                    # 计算拉索夹角余弦乘索长
                    base = np.sqrt((ops.nodeCoord(tower_node)[0] - ops.nodeCoord(girder_node)[0]) ** 2 + \
                                (ops.nodeCoord(tower_node)[1] - ops.nodeCoord(girder_node)[1]) ** 2)
                    # 计算拉索长度
                    ele_len = element_len_cal(tower_node, girder_node)
                    # 计算拉索夹角正弦
                    cable_sin = abs(ops.nodeCoord(tower_node)[2] - ops.nodeCoord(girder_node)[2]) / ele_len
                    # 计算折减后的钢索弹性模量
                    ernst_moduls = elastic_modulus / (1 + elastic_modulus * 1000 * \
                                                    (cable_density * base) ** 2 / (12 * work_stress ** 3))
                    ernst_moduls = ernst_moduls * 1e6  # 将单位转换为Pa
                    
                    # 建立材料和截面信息
                    para_tag_1_1 = para_tag_0 + cable_count
                    para_tag_1_2 = para_tag_0 + cable_count + 5000

                    cable_A = cable_area_list[j][i]
                    if cable_f_list != []:
                        cable_f = cable_f_list[j][i]
                    elif cable_plane_num == 1:
                        cable_f = girder_G_list[j][i] / cable_sin
                        if cable_f_return_index:
                            temp_origin_f_list.append(cable_f)
                    else:
                        cable_f = girder_G_list[j][i] / 2 / cable_sin
                        if cable_f_return_index:
                            temp_origin_f_list.append(cable_f)
                    cable_E = ernst_moduls

                    # ops.uniaxialMaterial('Elastic', para_tag_1_1, cable_E, 0.0, 1)
                    ops.uniaxialMaterial('Elastic', para_tag_1_1, cable_E)

                    cable_stress = cable_f / cable_A
                    cable_strain = cable_stress / cable_E

                    ops.uniaxialMaterial('InitStrainMaterial', para_tag_1_2, para_tag_1_1, cable_strain)

                    
                    cable_mass = ['-rho', cable_density * cable_A / 9.8 * 1000, '-cMass', 1]
                    cable_damp = ['-doRayleigh', 1]

                    # skeleton['materials'][para_tag_1_1] = {"matType": "Elastic", "E_mod": cable_E, \
                    #                                        "nu":None, "rho": cable_density * cable_A / 9.8 * 1000}
                    skeleton['sections'][para_tag_1_2] = {"secType": "elasticSection", "E_mod": cable_E, "area": cable_A, \
                                        "Iz": 0, "Iy": 0, "Jxx": 0, "G_mod": 0, \
                                        "rho" : cable_density * cable_A / 9.8 * 1000}
                    
                    # 建立单元
                    ele_tag = ele_tag_0 + cable_count
#                     ops.element('Truss', ele_tag, tower_node, girder_node, cable_A, \
#                                    para_tag_1_2, *cable_mass, *cable_damp)
                    ops.element('corotTruss', ele_tag, tower_node, girder_node, cable_A, \
                                   para_tag_1_2, *cable_mass, *cable_damp)
                    skeleton['elements'][ele_tag] = {"eleType": "Truss", "eleNodesTags": [tower_node, girder_node], \
                                                        "secTag": para_tag_1_2, \
                                                        "rho": cable_density * cable_A / 9.8 * 1000, "cMass": "-cMass"}
                    
                    # 重力荷载建立
                    if gravity_index:
                        sec_info_dict[para_tag_1_2] = [[cable_density], [cable_A]]
                        element_G_load_create(para_tag_1_2, ele_len, sec_info_dict, \
                                                  tower_node, girder_node)
                        
                if cable_f_return_index:
                    origin_cable_f_list[0].append(temp_origin_f_list)


        
    # 对称边索面建立
    if cable_plane_num == 2 or cable_plane_num == 3:
        
        cable_count = 0  # 累计建立的拉索单元数量
        ele_tag_0 = 30100000
        para_tag_0 = 10000
        
        cable_area_list = cable_area_list_1

        # 边索面拉索索力数据
        if cable_f_list_1 == None and cable_f_list_2 == None:
            cable_f_list = []
        else:
            cable_f_list = cable_f_list_1

        # 按索面顺序建立拉索单元
        for j in range(tower_num*2):
            tower_index = j // 2  # 当前主塔序号

            # 根据主塔序号确定主塔锚固节点编号序列
            tower_start_node = anchor_nodes_range_list[tower_index][0]
            tower_end_node = anchor_nodes_range_list[tower_index][1]
            tower_node_list = np.linspace(tower_start_node, tower_end_node, \
                                          int(abs(tower_end_node - tower_start_node) + 1))  # 包含非锚固关键节点
            
            girder_start_node_0 = no_anchor_num_side_1 * (insert_node_num + 1) + 1  # 最初的加劲梁锚固节点编号
            
            # 根据索面位置确定加劲梁锚固节点编号序列
            if j == 0:
                girder_start_node = girder_start_node_0
                girder_end_node = girder_start_node + (cable_num - 1) * (insert_node_num + 1)
                girder_node_list = np.linspace(girder_start_node, girder_end_node, \
                                            int(girder_end_node - girder_start_node + 1))  # 包含插入节点
            
            # 靠主塔y轴正半区方向的索面
            elif j % 2 == 1:
                girder_start_node = girder_end_node + 2 * no_anchor_num_tower * (insert_node_num + 1)
                girder_end_node = girder_start_node + (cable_num - 1) * (insert_node_num + 1)
                girder_node_list = np.linspace(girder_end_node, girder_start_node, \
                                               int(girder_end_node - girder_start_node + 1))  # 包含插入节点
            
            # 靠主塔y轴负半区方向的索面
            else:
                girder_start_node = girder_end_node + no_anchor_num_middle * (insert_node_num + 1)
                girder_end_node = girder_start_node + (cable_num - 1) * (insert_node_num + 1)
                girder_node_list = np.linspace(girder_start_node, girder_end_node, \
                                               int(girder_end_node - girder_start_node + 1))  # 包含插入节点
                
            if cable_f_return_index:
                temp_origin_f_list = []
            
            # 靠主塔y轴正半区方向的索面
            if j % 2 == 1:
                # 逐对拉索建立单元
                for i in range(cable_num):
                    cable_count += 1
                    girder_node_2 = 20200000 + int(girder_node_list[i*(insert_node_num+1)])  # 拉索加劲梁纵梁2锚固节点
                    girder_node_3 = 20300000 + int(girder_node_list[i*(insert_node_num+1)])  # 拉索加劲梁纵梁3锚固节点
                    
                    while tower_node_list[0] in no_anchor_nodes_list[tower_index]:
                        # 排除主塔锚固区非锚固节点
                        tower_node_list = tower_node_list[1:]
                        
                    tower_node_3 = 10101000 + tower_index * 100000 + int(tower_node_list[0])  # 拉索主塔分支3锚固节点
                    tower_node_4 = 10101000 + tower_index * 100000 + int(tower_node_list[0])  # 拉索主塔分支4锚固节点
                    tower_node_list = tower_node_list[1:]

                    if ops.nodeCoord(tower_node_3)[1] != tower_center_loc_list[tower_index][1]:
                        # 当拉索需要锚固在第3分支时
                        tower_node_3 = tower_node_3 + 2000
                        tower_node_4 = tower_node_4 + 2000

                        if ops.nodeCoord(tower_node_3)[0] != tower_center_loc_list[tower_index][0]:
                            # 当拉索需要锚固在第4分支时
                            tower_node_4 = tower_node_4 + 1000

                    elif ops.nodeCoord(tower_node_3)[0] != tower_center_loc_list[tower_index][0]:
                        # 当拉索需要锚固在第2分支时
                        tower_node_3 = tower_node_3 + 1000
                    
                    # 加劲梁纵梁2拉索
                    # 计算拉索夹角余弦乘索长(尽管通常情况下存在对称性，但仍然分开计算两面拉索的数据)
                    base_2 = np.sqrt((ops.nodeCoord(tower_node_4)[0] - ops.nodeCoord(girder_node_2)[0]) ** 2 + \
                                (ops.nodeCoord(tower_node_4)[1] - ops.nodeCoord(girder_node_2)[1]) ** 2)
                    # 计算拉索长度
                    ele_len_2 = element_len_cal(tower_node_4, girder_node_2)
                    # 计算拉索夹角正弦
                    cable_sin = abs(ops.nodeCoord(tower_node_4)[2] - ops.nodeCoord(girder_node_2)[2]) / ele_len_2
                    # 计算折减后的钢索弹性模量
                    ernst_moduls_2 = elastic_modulus / (1 + elastic_modulus * 1000 * \
                                                    (cable_density * base_2) ** 2 / (12 * work_stress ** 3))
                    ernst_moduls_2 = ernst_moduls_2 * 1e6  # 将单位转换为Pa

                    # 加劲梁纵梁3拉索
                    # 计算拉索夹角余弦乘索长(尽管通常情况下存在对称性，但仍然分开计算两面拉索的数据)
                    base_3 = np.sqrt((ops.nodeCoord(tower_node_3)[0] - ops.nodeCoord(girder_node_3)[0]) ** 2 + \
                                (ops.nodeCoord(tower_node_3)[1] - ops.nodeCoord(girder_node_3)[1]) ** 2)
                    # 计算拉索长度
                    ele_len_3 = element_len_cal(tower_node_3, girder_node_3)
                    # 计算折减后的钢索弹性模量
                    ernst_moduls_3 = elastic_modulus / (1 + elastic_modulus * 1000 * \
                                                    (cable_density * base_3) ** 2 / (12 * work_stress ** 3))
                    ernst_moduls_3 = ernst_moduls_3 * 1e6  # 将单位转换为Pa

                    # 建立材料和截面信息
                    para_tag_2_1 = para_tag_0 + 10000 + cable_count
                    para_tag_2_2 = para_tag_0 + 10000 + cable_count + 5000
                    para_tag_3_1 = para_tag_0 + 20000 + cable_count
                    para_tag_3_2 = para_tag_0 + 20000 + cable_count + 5000

                    cable_A = cable_area_list[j][i]
                    if cable_f_list != []:
                        cable_f = cable_f_list[j][i]
                    elif cable_plane_num == 3:
                        cable_f = girder_G_list[j][i] / 4 / cable_sin
                        if cable_f_return_index:
                            temp_origin_f_list.append(cable_f)
                    else:
                        cable_f = girder_G_list[j][i] / 2 / cable_sin
                        if cable_f_return_index:
                            temp_origin_f_list.append(cable_f)
                    cable_E = ernst_moduls_2

                    # ops.uniaxialMaterial('Elastic', para_tag_2_1, cable_E, 0.0, 1)
                    ops.uniaxialMaterial('Elastic', para_tag_2_1, cable_E)
                    # ops.uniaxialMaterial('Elastic', para_tag_3_1, cable_E, 0.0, 1)
                    ops.uniaxialMaterial('Elastic', para_tag_3_1, cable_E)

                    cable_stress = cable_f / cable_A
                    cable_strain = cable_stress / cable_E

                    ops.uniaxialMaterial('InitStrainMaterial', para_tag_2_2, para_tag_2_1, cable_strain)
                    ops.uniaxialMaterial('InitStrainMaterial', para_tag_3_2, para_tag_3_1, cable_strain)

                    
                    cable_mass = ['-rho', cable_density * cable_A / 9.8 * 1000, '-cMass', 1]
                    cable_damp = ['-doRayleigh', 1]

                    skeleton['sections'][para_tag_2_2] = {"secType": "elasticSection", "E_mod": cable_E, "area": cable_A, \
                                        "Iz": 0, "Iy": 0, "Jxx": 0, "G_mod": 0, \
                                        "rho" : cable_density * cable_A / 9.8 * 1000}
                    skeleton['sections'][para_tag_3_2] = {"secType": "elasticSection", "E_mod": cable_E, "area": cable_A, \
                                        "Iz": 0, "Iy": 0, "Jxx": 0, "G_mod": 0, \
                                        "rho" : cable_density * cable_A / 9.8 * 1000}
                    
                    # 建立单元
                    ele_tag_2 = ele_tag_0 + 100000 + cable_count
#                     ops.element('Truss', ele_tag_2, tower_node_4, girder_node_2, cable_A, \
#                                    para_tag_2_2, *cable_mass, *cable_damp)
                    ops.element('corotTruss', ele_tag_2, tower_node_4, girder_node_2, cable_A, \
                                   para_tag_2_2, *cable_mass, *cable_damp)
                    skeleton['elements'][ele_tag_2] = {"eleType": "Truss", "eleNodesTags": [tower_node_4, girder_node_2], \
                                                        "secTag": para_tag_2_2, \
                                                        "rho": cable_density * cable_A / 9.8 * 1000, "cMass": "-cMass"}
                    
                    ele_tag_3 = ele_tag_0 + 200000 + cable_count
#                     ops.element('Truss', ele_tag_3, tower_node_3, girder_node_3, cable_A, \
#                                    para_tag_2_2, *cable_mass, *cable_damp)
                    ops.element('corotTruss', ele_tag_3, tower_node_3, girder_node_3, cable_A, \
                                   para_tag_2_2, *cable_mass, *cable_damp)
                    skeleton['elements'][ele_tag_3] = {"eleType": "Truss", "eleNodesTags": [tower_node_3, girder_node_3], \
                                                        "secTag": para_tag_2_2, \
                                                        "rho": cable_density * cable_A / 9.8 * 1000, "cMass": "-cMass"}
                    
                    # 重力荷载建立
                    if gravity_index:
                        sec_info_dict[para_tag_2_2] = [[cable_density], [cable_A]]
                        element_G_load_create(para_tag_2_2, ele_len_2, sec_info_dict, \
                                                  tower_node_4, girder_node_2)
                        
                        sec_info_dict[para_tag_3_2] = [[cable_density], [cable_A]]
                        element_G_load_create(para_tag_3_2, ele_len_3, sec_info_dict, \
                                                  tower_node_3, girder_node_3)
                        
                if cable_f_return_index:
                    origin_cable_f_list[0].append(temp_origin_f_list)

            
            # 靠主塔y轴负半区方向的索面
            else:
                # 逐对拉索建立单元
                for i in range(cable_num):

                    cable_count += 1
                    girder_node_2 = 20200000 + int(girder_node_list[i*(insert_node_num+1)])  # 拉索加劲梁纵梁2锚固节点
                    girder_node_3 = 20300000 + int(girder_node_list[i*(insert_node_num+1)])  # 拉索加劲梁纵梁3锚固节点

                    while tower_node_list[0] in no_anchor_nodes_list[tower_index]:
                        # 排除主塔锚固区非锚固节点
                        tower_node_list = tower_node_list[1:]
                    
                    tower_node_1 = 10101000 + tower_index * 100000 + int(tower_node_list[0])  # 拉索主塔分支1锚固节点
                    tower_node_2 = 10101000 + tower_index * 100000 + int(tower_node_list[0])  # 拉索主塔分支2锚固节点
                    tower_node_list = tower_node_list[1:]
                    
                    if ops.nodeCoord(tower_node_1)[0] != tower_center_loc_list[tower_index][0]:
                        # 当主塔存在第2分支时
                        tower_node_2 = tower_node_2 + 1000
                    else:
                        pass
                    
                    # 加劲梁纵梁2拉索
                    # 计算拉索夹角余弦乘索长(尽管通常情况下存在对称性，但仍然分开计算两面拉索的数据)
                    base_2 = np.sqrt((ops.nodeCoord(tower_node_1)[0] - ops.nodeCoord(girder_node_2)[0]) ** 2 + \
                                (ops.nodeCoord(tower_node_1)[1] - ops.nodeCoord(girder_node_2)[1]) ** 2)
                    # 计算拉索长度
                    ele_len_2 = element_len_cal(tower_node_1, girder_node_2)
                    # 计算拉索夹角正弦
                    cable_sin = abs(ops.nodeCoord(tower_node_1)[2] - ops.nodeCoord(girder_node_2)[2]) / ele_len_2
                    # 计算折减后的钢索弹性模量
                    ernst_moduls_2 = elastic_modulus / (1 + elastic_modulus * 1000 * \
                                                    (cable_density * base_2) ** 2 / (12 * work_stress ** 3))
                    ernst_moduls_2 = ernst_moduls_2 * 1e6  # 将单位转换为Pa
                    
                    # 加劲梁纵梁3拉索
                    # 计算拉索夹角余弦乘索长(尽管通常情况下存在对称性，但仍然分开计算两面拉索的数据)
                    base_3 = np.sqrt((ops.nodeCoord(tower_node_2)[0] - ops.nodeCoord(girder_node_3)[0]) ** 2 + \
                                (ops.nodeCoord(tower_node_2)[1] - ops.nodeCoord(girder_node_3)[1]) ** 2)
                    # 计算拉索长度
                    ele_len_3 = element_len_cal(tower_node_2, girder_node_3)
                    # 计算折减后的钢索弹性模量
                    ernst_moduls_3 = elastic_modulus / (1 + elastic_modulus * 1000 * \
                                                    (cable_density * base_3) ** 2 / (12 * work_stress ** 3))
                    ernst_moduls_3 = ernst_moduls_3 * 1e6  # 将单位转换为Pa

                    # 建立材料和截面信息
                    para_tag_2_1 = para_tag_0 + 10000 + cable_count
                    para_tag_2_2 = para_tag_0 + 10000 + cable_count + 5000
                    para_tag_3_1 = para_tag_0 + 20000 + cable_count
                    para_tag_3_2 = para_tag_0 + 20000 + cable_count + 5000

                    cable_A = cable_area_list[j][i]
                    if cable_f_list != []:
                        cable_f = cable_f_list[j][i]
                    elif cable_plane_num == 3:
                        cable_f = girder_G_list[j][i] / 4 / cable_sin
                        if cable_f_return_index:
                            temp_origin_f_list.append(cable_f)
                    else:
                        cable_f = girder_G_list[j][i] / 2 / cable_sin
                        if cable_f_return_index:
                            temp_origin_f_list.append(cable_f)
                    cable_E = ernst_moduls_2

                    # ops.uniaxialMaterial('Elastic', para_tag_2_1, cable_E, 0.0, 1)
                    ops.uniaxialMaterial('Elastic', para_tag_2_1, cable_E)
                    # ops.uniaxialMaterial('Elastic', para_tag_3_1, cable_E, 0.0, 1)
                    ops.uniaxialMaterial('Elastic', para_tag_3_1, cable_E)

                    cable_stress = cable_f / cable_A
                    cable_strain = cable_stress / cable_E

                    ops.uniaxialMaterial('InitStrainMaterial', para_tag_2_2, para_tag_2_1, cable_strain)
                    ops.uniaxialMaterial('InitStrainMaterial', para_tag_3_2, para_tag_3_1, cable_strain)

                    
                    cable_mass = ['-rho', cable_density * cable_A / 9.8 * 1000, '-cMass', 1]
                    cable_damp = ['-doRayleigh', 1]

                    skeleton['sections'][para_tag_2_2] = {"secType": "elasticSection", "E_mod": cable_E, "area": cable_A, \
                                        "Iz": 0, "Iy": 0, "Jxx": 0, "G_mod": 0, \
                                        "rho" : cable_density * cable_A / 9.8 * 1000}
                    skeleton['sections'][para_tag_3_2] = {"secType": "elasticSection", "E_mod": cable_E, "area": cable_A, \
                                        "Iz": 0, "Iy": 0, "Jxx": 0, "G_mod": 0, \
                                        "rho" : cable_density * cable_A / 9.8 * 1000}
                    
                    # 建立单元
                    ele_tag_2 = ele_tag_0 + 100000 + cable_count
#                     ops.element('Truss', ele_tag_2, tower_node_1, girder_node_2, cable_A, \
#                                    para_tag_2_2, *cable_mass, *cable_damp)
                    ops.element('corotTruss', ele_tag_2, tower_node_1, girder_node_2, cable_A, \
                                   para_tag_2_2, *cable_mass, *cable_damp)
                    skeleton['elements'][ele_tag_2] = {"eleType": "Truss", "eleNodesTags": [tower_node_1, girder_node_2], \
                                                        "secTag": para_tag_2_2, \
                                                        "rho": cable_density * cable_A / 9.8 * 1000, "cMass": "-cMass"}
                    
                    ele_tag_3 = ele_tag_0 + 200000 + cable_count
#                     ops.element('Truss', ele_tag_3, tower_node_2, girder_node_3, cable_A, \
#                                    para_tag_2_2, *cable_mass, *cable_damp)
                    ops.element('corotTruss', ele_tag_3, tower_node_2, girder_node_3, cable_A, \
                                   para_tag_2_2, *cable_mass, *cable_damp)
                    skeleton['elements'][ele_tag_3] = {"eleType": "Truss", "eleNodesTags": [tower_node_2, girder_node_3], \
                                                        "secTag": para_tag_2_2, \
                                                        "rho": cable_density * cable_A / 9.8 * 1000, "cMass": "-cMass"}
                    
                    # 重力荷载建立
                    if gravity_index:
                        sec_info_dict[para_tag_2_2] = [[cable_density], [cable_A]]
                        element_G_load_create(para_tag_2_2, ele_len_2, sec_info_dict, \
                                                  tower_node_1, girder_node_2)
                        
                        sec_info_dict[para_tag_3_2] = [[cable_density], [cable_A]]
                        element_G_load_create(para_tag_3_2, ele_len_3, sec_info_dict, \
                                                  tower_node_2, girder_node_3)
                        
                if cable_f_return_index:
                    origin_cable_f_list[0].append(temp_origin_f_list)
    
    
    
    # 其他情况
    if cable_plane_num not in [1, 2, 3]:
        print('程序尚不支持！')

    if cable_f_return_index: 
        return origin_cable_f_list




# 墩建模
def column_modelling(main_span_len, main_span_num, side_span_len_1, side_span_len_2, \
                        girder_width, lo_node_num, insert_node_num, \
                        col_sec_para_1, col_mat_para_1, col_h_1, \
                        col_div_num, \
                        skeleton, \
                        gravity_index=0, load_pattern_tag=-1, time_series_tag=-1, \
                        col_loc_2=None, col_loc_3=None, \
                        col_sec_para_2=None, col_mat_para_2=None, col_h_2=None, \
                        col_sec_para_3=None, col_mat_para_3=None, col_h_3=None):
    
    # =========过渡墩、辅助墩建模=========
    # 思路：根据过渡墩、辅助墩的大致位置寻找最接近的虚拟横梁节点
    # 与虚拟横梁节点留出*0.5m*的间隔（留给支座单元）后，根据墩高建立墩的节点与单元
    # 
    # 数据格式：
    # main_span_len = 主跨跨径
    # main_span_num = 主跨数量
    # side_span_len_1 = 边跨（y轴负半区）跨径
    # side_span_len_2 = 边跨（y轴正半区）跨径
    # girder_width = 加劲梁宽度
    # 
    # lo_node_num = 加劲梁纵梁节点数
    # insert_node_num = 加劲梁加密节点数
    #
    # col_sec_para_1 = 过渡墩截面参数 = [[截面积，Iz，Iy，Jxx], [截面积，Iz，Iy，Jxx]]（前者为y轴负半区过渡墩，下同）
    # col_mat_para_1 = 过渡墩材料参数 = [[材料密度，材料弹性模量，材料剪切模量], [材料密度，材料弹性模量，材料剪切模量]]
    # col_h_1 = 过渡墩高度 = [过渡墩高度1, 过渡墩高度2]
    # 
    # col_div_num = 墩单元划分数量
    # 
    # skeleton = 桥梁骨架信息
    # 
    # load_pattern_tag = 荷载pattern编号
    # time_series_tag = 时间序列序号
    # gravity_index = 墩建模是否同时进行重力荷载建模
    # 
    # col_loc_1 = y轴负半区侧辅助墩位置 = [辅助墩1位置, ...]（位置由边跨百分比表示，起点为边端）
    # col_loc_2 = y轴正半区侧辅助墩位置 = [辅助墩1位置, ...]（位置由边跨百分比表示，起点为边端）
    # col_sec_para_2 = y轴负半区辅助墩截面参数 = [[截面积，Iz，Iy，Jxx], ...]
    # col_mat_para_2 = y轴负半区辅助墩材料参数 = [[材料密度，材料弹性模量，材料剪切模量], ...]
    # col_sec_para_3 = y轴正半区辅助墩截面参数 = [[截面积，Iz，Iy，Jxx], ...]
    # col_h_2 = 辅助墩高度 = [辅助墩高度1, 辅助墩高度2, ...]
    # col_mat_para_3 = y轴正半区辅助墩材料参数 = [[材料密度，材料弹性模量，材料剪切模量], ...]
    # col_h_3 = 辅助墩高度 = [辅助墩高度1, 辅助墩高度2, ...]
    # *以上辅助墩的截面和材料参数数组元素的排序与位置参数数组的元素排序相同
    
    
    # =========节点定义=========
    # 节点命名规则：
    # 墩的节点采用八位整数命名，千万位为4表示墩结构
    # 百万位与十万位表示墩位于桥梁哪一侧（y轴方向），00表示y轴负半区一侧，01表示y轴正半区一侧
    # 万位表示墩位于桥梁哪一侧（x轴方向），0表示位于x轴负半区一侧，1表示x轴正半区一侧
    # 千位表示属于过渡墩还是辅助墩，0表示过渡墩，1表示辅助墩
    # 辅助墩的百位表示辅助墩编号，其余两位为节点序号
    # 过渡墩其余三位为节点序号
    
    support_h = 0  # 预留支座高度——取为0，采用零长度单元模拟支座
    
    kwargs_1 = {'marker': '.', 'color': 'b', 's': 3, 'alpha': 1}

    # y轴负半区过渡墩节点定义
    node_z_start = ops.nodeCoord(20100001)[2] - support_h
    node_z_end = node_z_start - col_h_1[0]
    node_z_interval = np.linspace(node_z_start, node_z_end, col_div_num+1)
    
    for i in range(col_div_num + 1):
        node_tag_1 = 40000001 + i
        node_tag_2 = 40010001 + i
        
        node_x_1 = - girder_width / 2
        node_x_2 = girder_width / 2

        node_y_1 = ops.nodeCoord(20100001)[1]
        node_y_2 = ops.nodeCoord(20100001)[1]
        
        node_z_1 = node_z_interval[i]
        node_z_2 = node_z_interval[i]
        
        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}

        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
    
    # y轴正半区过渡墩节点定义
    node_z_start = ops.nodeCoord(20100000 + lo_node_num)[2] - support_h
    node_z_end = node_z_start - col_h_1[1]
    node_z_interval = np.linspace(node_z_start, node_z_end, col_div_num+1)
    
    for i in range(col_div_num + 1):
        node_tag_1 = 40100001 + i
        node_tag_2 = 40110001 + i
        
        node_x_1 = - girder_width / 2
        node_x_2 = girder_width / 2

        node_y_1 = ops.nodeCoord(20100000 + lo_node_num)[1]
        node_y_2 = ops.nodeCoord(20100000 + lo_node_num)[1]
        
        node_z_1 = node_z_interval[i]
        node_z_2 = node_z_interval[i]
        
        ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
        skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}

        ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
        skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
    
    # 确定辅助墩的节点编号
    auxi_col_node_list_1 = []  # y轴负半区辅助墩对应加劲梁节点编号
    auxi_col_node_list_2 = []  # y轴正半区辅助墩对应加劲梁节点编号
    
    # y轴负半区辅助墩
    if col_loc_2 != None:
        for i in range(len(col_loc_2)):
            node_tag = 20100001
            y_0 = ops.nodeCoord(node_tag)[1]  # 边端节点y坐标

            while (ops.nodeCoord(node_tag+1)[1]-y_0)/side_span_len_1 < col_loc_2[i]:
                node_tag += (1 + insert_node_num)
            
            auxi_col_node_list_1.append(node_tag)
    
    # y轴正半区辅助墩
    if col_loc_3 != None:
        for i in range(len(col_loc_3)):
            node_tag = 20100000 + lo_node_num
            y_0 = ops.nodeCoord(node_tag)[1]  # 边端节点y坐标
            
            while (y_0-ops.nodeCoord(node_tag-1)[1])/side_span_len_2 < col_loc_3[i]:
                node_tag -= (1 + insert_node_num)
            
            auxi_col_node_list_2.append(node_tag)
        
    
    # y轴负半区辅助墩节点定义
    if col_loc_2 != None:
        for i in range(len(col_loc_2)):
            node_y = ops.nodeCoord(auxi_col_node_list_1[i])[1]
            
            node_z_start = ops.nodeCoord(auxi_col_node_list_1[i])[2] - support_h
            node_z_end = node_z_start - col_h_2[i]
            node_z_interval = np.linspace(node_z_start, node_z_end, col_div_num+1)
            
            for j in range(col_div_num+1):
                node_tag_1 = 40001101 + i * 100 + j
                node_tag_2 = 40011101 + i * 100 + j

                node_x_1 = - girder_width / 2
                node_x_2 = girder_width / 2

                node_y_1 = node_y
                node_y_2 = node_y

                node_z_1 = node_z_interval[j]
                node_z_2 = node_z_interval[j]

                ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}

                ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
    
    # y轴正半区辅助墩节点定义
    if col_loc_3 != None:
        for i in range(len(col_loc_3)):
            node_y = ops.nodeCoord(auxi_col_node_list_2[i])[1]
            
            node_z_start = ops.nodeCoord(auxi_col_node_list_2[i])[2] - support_h
            node_z_end = node_z_start - col_h_3[i]
            node_z_interval = np.linspace(node_z_start, node_z_end, col_div_num+1)
            
            for j in range(col_div_num+1):
                node_tag_1 = 40101101 + i * 100 + j
                node_tag_2 = 40111101 + i * 100 + j

                node_x_1 = - girder_width / 2
                node_x_2 = girder_width / 2

                node_y_1 = node_y
                node_y_2 = node_y

                node_z_1 = node_z_interval[j]
                node_z_2 = node_z_interval[j]

                ops.node(node_tag_1, node_x_1, node_y_1, node_z_1)
                skeleton['nodes'][node_tag_1] = {'crds':[node_x_1, node_y_1, node_z_1], 'mass':None}

                ops.node(node_tag_2, node_x_2, node_y_2, node_z_2)
                skeleton['nodes'][node_tag_2] = {'crds':[node_x_2, node_y_2, node_z_2], 'mass':None}
    
    
    
    # =========单元定义=========
    # 截面和坐标系转换方式命名规则：
    # 采用四位整数命名，千位取值为1或2，1表示墩位于y轴负半区一侧，2表示墩位于y轴正半区一侧
    # 百位取值为0或1，0表示属于过渡墩，1表示属于辅助墩，其余两位表示墩序号
    # 单元命名规则：
    # 与节点命名规则相同，单元编号与靠上方的节点一致
    

    # 1-参数定义
    sp_1 = col_sec_para_1
    mp_1 = col_mat_para_1
    sp_2 = col_sec_para_2
    mp_2 = col_mat_para_2
    sp_3 = col_sec_para_3
    mp_3 = col_mat_para_3
    
    sec_info_dict = {}  # 墩截面信息字典（key-截面编号，value-[mp[i], sp[i]]）
    if gravity_index:
        ops.pattern('Plain', load_pattern_tag, time_series_tag)  # 需要进行重力建模时，建立荷载pattern
    
    # 过渡墩
    # 截面定义
    sec_tag_1 = 1001
    ops.section('Elastic', sec_tag_1, mp_1[0][1], sp_1[0][0], sp_1[0][1], sp_1[0][2], mp_1[0][2], sp_1[0][3])
    skeleton['sections'][sec_tag_1] = {"secType": "elasticSection", "E_mod": mp_1[0][1], "area": sp_1[0][0], \
                                    "Iz": sp_1[0][1], "Iy": sp_1[0][2], "Jxx": sp_1[0][3], "G_mod": mp_1[0][2], \
                                    "rho" : mp_1[0][0]}
    if gravity_index:
        sec_info_dict[sec_tag_1] = [mp_1[0], sp_1[0]]

    sec_tag_2 = 2001
    ops.section('Elastic', sec_tag_2, mp_1[1][1], sp_1[1][0], sp_1[1][1], sp_1[1][2], mp_1[1][2], sp_1[1][3])
    skeleton['sections'][sec_tag_2] = {"secType": "elasticSection", "E_mod": mp_1[1][1], "area": sp_1[1][0], \
                                    "Iz": sp_1[1][1], "Iy": sp_1[1][2], "Jxx": sp_1[1][3], "G_mod": mp_1[1][2], \
                                    "rho" : mp_1[1][0]}
    if gravity_index:
        sec_info_dict[sec_tag_2] = [mp_1[1], sp_1[1]]
    
    # 截面质量信息定义
    mass_1 = []
    mass_1.append(['-mass', mp_1[0][0]*sp_1[0][0], '-cMass'])  # 采用一致质量
    mass_1.append(['-mass', mp_1[1][0]*sp_1[1][0], '-cMass'])  # 采用一致质量
    
    # 坐标转换方式定义
    trans_tag_1 = 1001
    trans_tag_2 = 2001
    ops.geomTransf('Linear', trans_tag_1, *[1.0, 0.0, 0.0])
    ops.geomTransf('Linear', trans_tag_2, *[1.0, 0.0, 0.0])
    
    # 辅助墩（y轴负半区）
    # 截面定义
    if col_loc_2 != None:
        mass_2 = []
        for i in range(len(col_loc_2)):
            sec_tag = 1101 + i
            ops.section('Elastic', sec_tag, mp_2[i][1], sp_2[i][0], sp_2[i][1], sp_2[i][2], mp_2[i][2], sp_2[i][3])
            skeleton['sections'][sec_tag] = {"secType": "elasticSection", "E_mod": mp_2[i][1], "area": sp_2[i][0], \
                                            "Iz": sp_2[i][1], "Iy": sp_2[i][2], "Jxx": sp_2[i][3], "G_mod": mp_2[i][2], \
                                            "rho" : mp_2[i][0]}
            if gravity_index:
                sec_info_dict[sec_tag] = [mp_2[i], sp_2[i]]

            # 截面质量信息定义
            mass_2.append(['-mass', mp_2[i][0]*sp_2[i][0], '-cMass'])  # 采用一致质量

            # 坐标转换方式定义
            trans_tag = 1101 + i
            ops.geomTransf('Linear', trans_tag, *[1.0, 0.0, 0.0])
    
    # 辅助墩（y轴正半区）
    # 截面定义
    if col_loc_3 != None:
        mass_3 = []
        for i in range(len(col_loc_3)):
            sec_tag = 2101 + i
            ops.section('Elastic', sec_tag, mp_3[i][1], sp_3[i][0], sp_3[i][1], sp_3[i][2], mp_3[i][2], sp_3[i][3])
            skeleton['sections'][sec_tag] = {"secType": "elasticSection", "E_mod": mp_3[i][1], "area": sp_3[i][0], \
                                            "Iz": sp_3[i][1], "Iy": sp_3[i][2], "Jxx": sp_3[i][3], "G_mod": mp_3[i][2], \
                                            "rho" : mp_3[i][0]}
            if gravity_index:
                sec_info_dict[sec_tag] = [mp_3[i], sp_3[i]]

            # 截面质量信息定义
            mass_3.append(['-mass', mp_3[i][0]*sp_3[i][0], '-cMass'])  # 采用一致质量

            # 坐标转换方式定义
            trans_tag = 2101 + i
            ops.geomTransf('Linear', trans_tag, *[1.0, 0.0, 0.0])
    
    
    # 2-单元定义
    # y轴负半区过渡墩单元定义
    for i in range(col_div_num):
        ele_tag_1 = 40000001 + i
        ele_tag_2 = 40010001 + i
        
        node_1_tag_1 = 40000001 + i
        node_2_tag_1 = 40000002 + i
        node_1_tag_2 = 40010001 + i
        node_2_tag_2 = 40010002 + i
        
        sec_tag = 1001
        trans_tag = 1001
        
        ops.element('elasticBeamColumn', ele_tag_1, node_1_tag_1, node_2_tag_1, sec_tag, trans_tag, *mass_1[0])
        skeleton['elements'][ele_tag_1] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag_1, node_2_tag_1], \
                                            "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}
        # 重力荷载建立
        if gravity_index:
            ele_len = element_len_cal(node_1_tag_1, node_2_tag_1)
            element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                        node_1_tag_1, node_2_tag_1)
            
        ops.element('elasticBeamColumn', ele_tag_2, node_1_tag_2, node_2_tag_2, sec_tag, trans_tag, *mass_1[0])
        skeleton['elements'][ele_tag_2] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag_2, node_2_tag_2], \
                                            "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}
        # 重力荷载建立
        if gravity_index:
            ele_len = element_len_cal(node_1_tag_2, node_2_tag_2)
            element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                        node_1_tag_2, node_2_tag_2)
        
        ele_loc_0 = [[], [], []]
        ele_loc_0[0].append(ops.nodeCoord(node_1_tag_1)[0])
        ele_loc_0[0].append(ops.nodeCoord(node_2_tag_1)[0])

        ele_loc_0[1].append(ops.nodeCoord(node_1_tag_1)[1])
        ele_loc_0[1].append(ops.nodeCoord(node_2_tag_1)[1])

        ele_loc_0[2].append(ops.nodeCoord(node_1_tag_1)[2])
        ele_loc_0[2].append(ops.nodeCoord(node_2_tag_1)[2])
        
        ele_loc_0 = [[], [], []]
        ele_loc_0[0].append(ops.nodeCoord(node_1_tag_2)[0])
        ele_loc_0[0].append(ops.nodeCoord(node_2_tag_2)[0])

        ele_loc_0[1].append(ops.nodeCoord(node_1_tag_2)[1])
        ele_loc_0[1].append(ops.nodeCoord(node_2_tag_2)[1])

        ele_loc_0[2].append(ops.nodeCoord(node_1_tag_2)[2])
        ele_loc_0[2].append(ops.nodeCoord(node_2_tag_2)[2])
    
    # y轴正半区过渡墩单元定义
    for i in range(col_div_num):
        ele_tag_1 = 40100001 + i
        ele_tag_2 = 40110001 + i
        
        node_1_tag_1 = 40100001 + i
        node_2_tag_1 = 40100002 + i
        node_1_tag_2 = 40110001 + i
        node_2_tag_2 = 40110002 + i
        
        sec_tag = 2001
        trans_tag = 2001
        
        ops.element('elasticBeamColumn', ele_tag_1, node_1_tag_1, node_2_tag_1, sec_tag, trans_tag, *mass_1[0])
        skeleton['elements'][ele_tag_1] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag_1, node_2_tag_1], \
                                            "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}
        # 重力荷载建立
        if gravity_index:
            ele_len = element_len_cal(node_1_tag_1, node_2_tag_1)
            element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                        node_1_tag_1, node_2_tag_1)
        ops.element('elasticBeamColumn', ele_tag_2, node_1_tag_2, node_2_tag_2, sec_tag, trans_tag, *mass_1[0])
        skeleton['elements'][ele_tag_2] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag_2, node_2_tag_2], \
                                            "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}
        # 重力荷载建立
        if gravity_index:
            ele_len = element_len_cal(node_1_tag_2, node_2_tag_2)
            element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                        node_1_tag_2, node_2_tag_2)
        
        ele_loc_0 = [[], [], []]
        ele_loc_0[0].append(ops.nodeCoord(node_1_tag_1)[0])
        ele_loc_0[0].append(ops.nodeCoord(node_2_tag_1)[0])

        ele_loc_0[1].append(ops.nodeCoord(node_1_tag_1)[1])
        ele_loc_0[1].append(ops.nodeCoord(node_2_tag_1)[1])

        ele_loc_0[2].append(ops.nodeCoord(node_1_tag_1)[2])
        ele_loc_0[2].append(ops.nodeCoord(node_2_tag_1)[2])
        
        ele_loc_0 = [[], [], []]
        ele_loc_0[0].append(ops.nodeCoord(node_1_tag_2)[0])
        ele_loc_0[0].append(ops.nodeCoord(node_2_tag_2)[0])

        ele_loc_0[1].append(ops.nodeCoord(node_1_tag_2)[1])
        ele_loc_0[1].append(ops.nodeCoord(node_2_tag_2)[1])

        ele_loc_0[2].append(ops.nodeCoord(node_1_tag_2)[2])
        ele_loc_0[2].append(ops.nodeCoord(node_2_tag_2)[2])
        
        
    if col_loc_2 != None:
        # y轴负半区辅助墩单元定义
        for i in range(len(col_loc_2)):
            for j in range(col_div_num):
                ele_tag_1 = 40001101 + i * 100 + j
                ele_tag_2 = 40011101 + i * 100 + j

                node_1_tag_1 = 40001101 + i * 100 + j
                node_2_tag_1 = 40001102 + i * 100 + j
                node_1_tag_2 = 40011101 + i * 100 + j
                node_2_tag_2 = 40011102 + i * 100 + j

                sec_tag = 1101 + i
                trans_tag = 1101 + i

                ops.element('elasticBeamColumn', ele_tag_1, node_1_tag_1, node_2_tag_1, sec_tag, trans_tag, *mass_2[0])
                skeleton['elements'][ele_tag_1] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag_1, node_2_tag_1], \
                                                    "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}
                # 重力荷载建立
                if gravity_index:
                    ele_len = element_len_cal(node_1_tag_1, node_2_tag_1)
                    element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag_1, node_2_tag_1)
                    
                ops.element('elasticBeamColumn', ele_tag_2, node_1_tag_2, node_2_tag_2, sec_tag, trans_tag, *mass_2[0])
                skeleton['elements'][ele_tag_2] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag_2, node_2_tag_2], \
                                                    "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}
                # 重力荷载建立
                if gravity_index:
                    ele_len = element_len_cal(node_1_tag_2, node_2_tag_2)
                    element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag_2, node_2_tag_2)
                
                ele_loc_0 = [[], [], []]
                ele_loc_0[0].append(ops.nodeCoord(node_1_tag_1)[0])
                ele_loc_0[0].append(ops.nodeCoord(node_2_tag_1)[0])

                ele_loc_0[1].append(ops.nodeCoord(node_1_tag_1)[1])
                ele_loc_0[1].append(ops.nodeCoord(node_2_tag_1)[1])

                ele_loc_0[2].append(ops.nodeCoord(node_1_tag_1)[2])
                ele_loc_0[2].append(ops.nodeCoord(node_2_tag_1)[2])
                
                ele_loc_0 = [[], [], []]
                ele_loc_0[0].append(ops.nodeCoord(node_1_tag_2)[0])
                ele_loc_0[0].append(ops.nodeCoord(node_2_tag_2)[0])

                ele_loc_0[1].append(ops.nodeCoord(node_1_tag_2)[1])
                ele_loc_0[1].append(ops.nodeCoord(node_2_tag_2)[1])

                ele_loc_0[2].append(ops.nodeCoord(node_1_tag_2)[2])
                ele_loc_0[2].append(ops.nodeCoord(node_2_tag_2)[2])
    
    
    if col_loc_3 != None:
        # y轴正半区辅助墩单元定义
        for i in range(len(col_loc_3)):
            for j in range(col_div_num):
                ele_tag_1 = 40101101 + i * 100 + j
                ele_tag_2 = 40111101 + i * 100 + j

                node_1_tag_1 = 40101101 + i * 100 + j
                node_2_tag_1 = 40101102 + i * 100 + j
                node_1_tag_2 = 40111101 + i * 100 + j
                node_2_tag_2 = 40111102 + i * 100 + j

                sec_tag = 2101 + i
                trans_tag = 2101 + i

                ops.element('elasticBeamColumn', ele_tag_1, node_1_tag_1, node_2_tag_1, sec_tag, trans_tag, *mass_3[0])
                skeleton['elements'][ele_tag_1] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag_1, node_2_tag_1], \
                                                    "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}
                # 重力荷载建立
                if gravity_index:
                    ele_len = element_len_cal(node_1_tag_1, node_2_tag_1)
                    element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag_1, node_2_tag_1)
                    
                ops.element('elasticBeamColumn', ele_tag_2, node_1_tag_2, node_2_tag_2, sec_tag, trans_tag, *mass_3[0])
                skeleton['elements'][ele_tag_2] = {"eleType": "elasticBeamColumn", "eleNodesTags": [node_1_tag_2, node_2_tag_2], \
                                                    "vecxz": [1.0, 0.0, 0.0], "secTag": sec_tag, "cMass": "-cMass"}
                # 重力荷载建立
                if gravity_index:
                    ele_len = element_len_cal(node_1_tag_2, node_2_tag_2)
                    element_G_load_create(sec_tag, ele_len, sec_info_dict, \
                                                node_1_tag_2, node_2_tag_2)
                
                ele_loc_0 = [[], [], []]
                ele_loc_0[0].append(ops.nodeCoord(node_1_tag_1)[0])
                ele_loc_0[0].append(ops.nodeCoord(node_2_tag_1)[0])

                ele_loc_0[1].append(ops.nodeCoord(node_1_tag_1)[1])
                ele_loc_0[1].append(ops.nodeCoord(node_2_tag_1)[1])

                ele_loc_0[2].append(ops.nodeCoord(node_1_tag_1)[2])
                ele_loc_0[2].append(ops.nodeCoord(node_2_tag_1)[2])
                
                ele_loc_0 = [[], [], []]
                ele_loc_0[0].append(ops.nodeCoord(node_1_tag_2)[0])
                ele_loc_0[0].append(ops.nodeCoord(node_2_tag_2)[0])

                ele_loc_0[1].append(ops.nodeCoord(node_1_tag_2)[1])
                ele_loc_0[1].append(ops.nodeCoord(node_2_tag_2)[1])

                ele_loc_0[2].append(ops.nodeCoord(node_1_tag_2)[2])
                ele_loc_0[2].append(ops.nodeCoord(node_2_tag_2)[2])
                
    return auxi_col_node_list_1, auxi_col_node_list_2




# 边界条件建模
def boundary_modelling(tower_node_list, tower_center_loc_list, \
                            girder_node_list, lo_node_num, insert_node_num, col_div_num, \
                            boundary_tower, boundary_side, \
                            skeleton, \
                            auxi_col_node_list_1=[], auxi_col_node_list_2=[], \
                            boundary_auxi_1=[], boundary_auxi_2=[]):
    
    # =========边界条件（包括支承、连接等）建模=========
    # 思路：固结塔和墩的底部
    # 建立过渡墩、辅助墩和加劲梁之间的连接
    # 建立主塔和加劲梁之间的连接。对于非空间桥塔，约束的加劲梁为位于桥塔平面的一根虚拟横梁
    # 对于空间桥塔，约束的加劲梁为最靠近两条横桥向横梁的两根虚拟横梁
    # 在塔上建立刚臂，刚臂的末端位于加劲梁横梁的正下方
    # 支座采用零长度单元进行模拟
    # 
    # 数据格式：
    # tower_node_list = 各主塔附加刚臂节点编号数组 = [主塔1附加刚臂节点编号, 主塔2..., ...]
    # tower_center_loc_list = 各个主塔的定位中心点坐标 = [[主塔1...], [主塔2...], ...]
    # girder_node_list = 加劲梁主塔位置节点编号数组 = [主塔1..., 主塔2..., ...]
    # lo_node_num = 加劲梁纵梁节点数
    # insert_node_num = 加劲梁加密节点数
    # col_div_num = 墩单元划分数量
    # boundary_tower = 主塔支座自由度约束情况 = [[主塔1...], [主塔2...], ...]
    # boundary_side = 过渡墩支座自由度约束情况 = [[y轴负半区过渡墩...], [y轴正半区过渡墩...]]
    # 
    # skeleton = 桥梁骨架信息
    # 
    # auxi_col_node_list_1 = 辅助墩（y轴负半区）位置加劲梁节点编号数组 = [辅助墩1..., 辅助墩2..., ...]
    # auxi_col_node_list_2 = 辅助墩（y轴正半区）位置加劲梁节点编号数组 = [辅助墩1..., 辅助墩2..., ...]
    # boundary_auxi_1 = 辅助墩（y轴负半区）支座自由度约束情况 = [[辅助墩1...], [辅助墩2...], ...]
    # boundary_auxi_2 = 辅助墩（y轴正半区）支座自由度约束情况 = [[辅助墩1...], [辅助墩2]..., ...]
    # 
    # 以上支座自由度约束信息通过一个包含六个整数元素的数组表示。六个元素取值为1或0，依次表示
    # x，y，z，rx，ry和rz方向的自由度约束情况（1为约束，0为释放）
    
    
    tower_num = len(tower_node_list)  # 主塔数量
    col_num_1 = len(auxi_col_node_list_1)  # 辅助墩（y轴负半区）数量
    col_num_2 = len(auxi_col_node_list_2)  # 辅助墩（y轴正半区）数量
    
    # 固结塔的底部
    for i in range(tower_num):
        node_tag_0 = 10101001 + i * 100000
        ops.fix(node_tag_0, *[1, 1, 1, 1, 1, 1])
        skeleton['spDofs'][node_tag_0] = [1, 1, 1, 1, 1, 1]
        if ops.nodeCoord(node_tag_0)[0] != tower_center_loc_list[i][0]:
            # 塔存在第二分支
            ops.fix(node_tag_0+1000, *[1, 1, 1, 1, 1, 1])
            skeleton['spDofs'][node_tag_0+1000] = [1, 1, 1, 1, 1, 1]
            if ops.nodeCoord(node_tag_0)[1] != tower_center_loc_list[i][1]:
                # 塔还存在第三四分支
                ops.fix(node_tag_0+2000, *[1, 1, 1, 1, 1, 1])
                skeleton['spDofs'][node_tag_0+2000] = [1, 1, 1, 1, 1, 1]
                ops.fix(node_tag_0+3000, *[1, 1, 1, 1, 1, 1])
                skeleton['spDofs'][node_tag_0+3000] = [1, 1, 1, 1, 1, 1]
        elif ops.nodeCoord(node_tag_0)[1] != tower_center_loc_list[i][1]:
            # 塔仅还存在第三分支
            ops.fix(node_tag_0+2000, *[1, 1, 1, 1, 1, 1])
            skeleton['spDofs'][node_tag_0+2000] = [1, 1, 1, 1, 1, 1]
    
    # 固结过渡墩的底部
    ops.fix(40000001+col_div_num, *[1, 1, 1, 1, 1, 1])
    skeleton['spDofs'][40000001+col_div_num] = [1, 1, 1, 1, 1, 1]
    ops.fix(40010001+col_div_num, *[1, 1, 1, 1, 1, 1])
    skeleton['spDofs'][40010001+col_div_num] = [1, 1, 1, 1, 1, 1]
    ops.fix(40100001+col_div_num, *[1, 1, 1, 1, 1, 1])
    skeleton['spDofs'][40100001+col_div_num] = [1, 1, 1, 1, 1, 1]
    ops.fix(40110001+col_div_num, *[1, 1, 1, 1, 1, 1])
    skeleton['spDofs'][40110001+col_div_num] = [1, 1, 1, 1, 1, 1]
    
    # 固结辅助墩（y轴负半区）的底部
    if col_num_1 != 0:
        for i in range(col_num_1):
            node_tag_1 = 40001101 + i * 100 + col_div_num
            node_tag_2 = 40011101 + i * 100 + col_div_num
            ops.fix(node_tag_1, *[1, 1, 1, 1, 1, 1])
            skeleton['spDofs'][node_tag_1] = [1, 1, 1, 1, 1, 1]
            ops.fix(node_tag_2, *[1, 1, 1, 1, 1, 1])
            skeleton['spDofs'][node_tag_2] = [1, 1, 1, 1, 1, 1]
            
    # 固结辅助墩（y轴正半区）的底部
    if col_num_2 != 0:
        for i in range(col_num_2):
            node_tag_1 = 40101101 + i * 100 + col_div_num
            node_tag_2 = 40111101 + i * 100 + col_div_num
            ops.fix(node_tag_1, *[1, 1, 1, 1, 1, 1])
            skeleton['spDofs'][node_tag_1] = [1, 1, 1, 1, 1, 1]
            ops.fix(node_tag_2, *[1, 1, 1, 1, 1, 1])
            skeleton['spDofs'][node_tag_2] = [1, 1, 1, 1, 1, 1]
    
    
    # 支座零长度单元材料定义
    uni_mat_tag_1 = 101
    uni_mat_tag_2 = 102
    ops.uniaxialMaterial('Elastic', uni_mat_tag_1, 1e10)  # 自由度约束方向上的材料
    ops.uniaxialMaterial('Elastic', uni_mat_tag_2, 1e-10)  # 自由度释放方向上的材料

    dir_list = [1, 2, 3, 4, 5, 6]  # 零长度单元方向数组

    # 将结构支座约束情况转换为材料编号
    for i in range(len(boundary_side)):
        for j in range(6):
            if boundary_side[i][j] == 1:
                boundary_side[i][j] = 101
            else:
                boundary_side[i][j] = 102

    for i in range(len(boundary_tower)):
        for j in range(6):
            if boundary_tower[i][j] == 1:
                boundary_tower[i][j] = 101
            else:
                boundary_tower[i][j] = 102
    
    if col_num_1 != 0:
        for i in range(len(boundary_auxi_1)):
            for j in range(6):
                if boundary_auxi_1[i][j] == 1:
                    boundary_auxi_1[i][j] = 101
                else:
                    boundary_auxi_1[i][j] = 102
    
    if col_num_2 != 0:
        for i in range(len(boundary_auxi_2)):
            for j in range(6):
                if boundary_auxi_2[i][j] == 1:
                    boundary_auxi_2[i][j] = 101
                else:
                    boundary_auxi_2[i][j] = 102

    
    # =========建立加劲梁与墩之间的支座单元=========
    # 单元命名规则：
    # 加劲梁与墩之间的支座单元采用八位整数命名，千万位为5表示连接结构
    # 百万位与十万位表示单元属于哪一种连接，01表示过渡墩，02表示辅助墩
    # 万位表示墩位于桥梁哪一侧（y轴方向），0表示位于y轴负半区一侧，1表示y轴正半区一侧
    # 千位表示墩位于桥梁哪一侧（x轴方向），0表示位于x轴负半区一侧，1表示x轴正半区一侧
    # 辅助墩的百位表示辅助墩编号，其余两位默认为01
    # 过渡墩的其余三位默认为001
    # 该单元截面假定为边长为1的正方形，刚度近似无穷大，质量为0
    
    # 过渡墩
    mat_tag_list = boundary_side[0]
    zero_ele_info = ['-mat', *mat_tag_list, '-dir', *dir_list]
    ops.element('zeroLength', 50100001, 20200001, 40000001, *zero_ele_info)
    ops.element('zeroLength', 50101001, 20300001, 40010001, *zero_ele_info)
    skeleton['equalDofs'][f'({20200001}, {40000001})'] = [0, 2]
    skeleton['equalDofs'][f'({20300001}, {40010001})'] = [0, 2]

    mat_tag_list = boundary_side[1]
    zero_ele_info = ['-mat', *mat_tag_list, '-dir', *dir_list]
    ops.element('zeroLength', 50110001, 20200000+lo_node_num, 40100001, *zero_ele_info)
    ops.element('zeroLength', 50111001, 20300000+lo_node_num, 40110001, *zero_ele_info)
    skeleton['equalDofs'][f'({20200000+lo_node_num}, {40100001})'] = [0, 2]
    skeleton['equalDofs'][f'({20300000+lo_node_num}, {40110001})'] = [0, 2]

    # 辅助墩（y轴负半区）
    if col_num_1 != 0:
        for i in range(col_num_1):
            ele_tag_1 = 50200101 + i * 100
            ele_tag_2 = 50201101 + i * 100
            
            node_1_tag_1 = auxi_col_node_list_1[i] + 100000
            node_2_tag_1 = 40001101 + i * 100
            node_1_tag_2 = auxi_col_node_list_1[i] + 200000
            node_2_tag_2 = 40011101 + i * 100

            mat_tag_list = boundary_auxi_1[i]
            zero_ele_info = ['-mat', *mat_tag_list, '-dir', *dir_list]
            
            ops.element('zeroLength', ele_tag_1, node_1_tag_1, node_2_tag_1, *zero_ele_info)
            skeleton['equalDofs'][f'({node_1_tag_1}, {node_2_tag_1})'] = [2]

            ops.element('zeroLength', ele_tag_2, node_1_tag_2, node_2_tag_2, *zero_ele_info)
            skeleton['equalDofs'][f'({node_1_tag_2}, {node_2_tag_2})'] = [2]
    
    # 辅助墩（y轴正半区）
    if col_num_2 != 0:
        for i in range(col_num_2):
            ele_tag_1 = 50210101 + i * 100
            ele_tag_2 = 50211101 + i * 100
            
            node_1_tag_1 = auxi_col_node_list_2[i] + 100000
            node_2_tag_1 = 40101101 + i * 100
            node_1_tag_2 = auxi_col_node_list_2[i] + 200000
            node_2_tag_2 = 40111101 + i * 100

            mat_tag_list = boundary_auxi_2[i]
            zero_ele_info = ['-mat', *mat_tag_list, '-dir', *dir_list]
            
            ops.element('zeroLength', ele_tag_1, node_1_tag_1, node_2_tag_1, *zero_ele_info)
            skeleton['equalDofs'][f'({node_1_tag_1}, {node_2_tag_1})'] = [2]

            ops.element('zeroLength', ele_tag_2, node_1_tag_2, node_2_tag_2, *zero_ele_info)
            skeleton['equalDofs'][f'({node_1_tag_2}, {node_2_tag_2})'] = [2]
    
    
    
    # =========建立加劲梁与主塔之间的支座节点与单元=========
    # 节点命名规则：
    # 加劲梁与墩之间的支座单元采用八位整数命名，千万位为5表示连接结构
    # 百万位与十万位表示单元属于哪一种连接，03表示主塔
    # 万位和千位表示主塔编号
    # 百位表示分支编号，其余两位默认为01（或01与02（同一主塔分支延伸出2个支座时））
    # 单元命名规则：
    # 百位及百位前与节点命名规则相同
    # 其余两位为01（与主塔连接的单元）或02（与加劲梁连接的单元）——同一主塔分支延伸出1个支座时
    # 其余两位为11或21（与主塔连接的单元）或12或22（与加劲梁连接的单元）——同一主塔分支延伸出2个支座时

    # 刚臂单元截面和质量性质定义
    sec_tag = 103
    ops.section('Elastic', sec_tag, 4e13, 1, 1/12, 1/12, 1.5e13, 1/6)
    skeleton['sections'][sec_tag] = {"secType": "elasticSection", "E_mod": 4e13, "area": 1, \
                                            "Iz": 1/12, "Iy": 1/12, "Jxx": 1/6, "G_mod": 1.5e13, \
                                            "rho" : 1}
    mass_0 = ['-mass', 1, '-cMass']  # 采用一致质量（加上了些微质量，防止质量矩阵病态）

    for i in range(tower_num):
        index_node_tag = 10101000 + i * 100000 + tower_node_list[i]
        # 当主塔与加劲梁接触段为位于xz平面的平面结构时
        if ops.nodeCoord(index_node_tag)[0] != tower_center_loc_list[i][1] and \
            ops.nodeCoord(index_node_tag)[1] == tower_center_loc_list[i][1]:
            
            # 建立辅助节点（与加劲梁节点重合）
            girder_node_tag_1 = 20200000 + girder_node_list[i]
            girder_node_tag_2 = 20300000 + girder_node_list[i]
            
            tower_node_tag_1 = 10101000 + i * 100000 + tower_node_list[i]
            tower_node_tag_2 = 10102000 + i * 100000 + tower_node_list[i]
            
            support_node_tag_1 = 50301101 + i * 1000
            support_node_tag_2 = 50301201 + i * 1000
            
            node_x = ops.nodeCoord(girder_node_tag_1)[0]
            node_y = ops.nodeCoord(girder_node_tag_1)[1]
            node_z = ops.nodeCoord(girder_node_tag_1)[2]
            
            ops.node(support_node_tag_1, node_x, node_y, node_z)
            ops.node(support_node_tag_2, -node_x, node_y, node_z)
            skeleton['nodes'][support_node_tag_1] = {'crds':[node_x, node_y, node_z], 'mass':None}
            skeleton['nodes'][support_node_tag_2] = {'crds':[-node_x, node_y, node_z], 'mass':None}

            # 建立刚臂单元
            # 建立刚臂单元坐标转换方式
            trans_tag_1 = i * 10 + 11
            trans_tag_2 = i * 10 + 12
            
            vector_x_1 = np.array([node_x - ops.nodeCoord(tower_node_tag_1)[0], \
                                   node_y - ops.nodeCoord(tower_node_tag_1)[1], \
                                   node_z - ops.nodeCoord(tower_node_tag_1)[2]])
            if vector_x_1[0] == 0 and vector_x_1[1] == 0:
                vector_z_1 = [1.0, 0.0, 0.0]
            else:
                vector_temp = np.array([0.0, 0.0, 1.0])
                vector_z_1 = np.cross(vector_x_1, vector_temp)
            ops.geomTransf('Linear', trans_tag_1, *vector_z_1)
            
            
            vector_x_2 = np.array([-node_x - ops.nodeCoord(tower_node_tag_2)[0], \
                                   node_y - ops.nodeCoord(tower_node_tag_2)[1], \
                                   node_z - ops.nodeCoord(tower_node_tag_2)[2]])
            if vector_x_2[0] == 0 and vector_x_2[1] == 0:
                vector_z_2 = [1.0, 0.0, 0.0]
            else:
                vector_temp = np.array([0.0, 0.0, 1.0])
                vector_z_2 = np.cross(vector_x_2, vector_temp)
            ops.geomTransf('Linear', trans_tag_2, *vector_z_2)
            
            ele_tag_1 = 50301101 + i * 1000
            ele_tag_2 = 50301201 + i * 1000
            
            ops.element('elasticBeamColumn', ele_tag_1, tower_node_tag_1, support_node_tag_1, \
                            sec_tag, trans_tag_1, *mass_0)
            ops.element('elasticBeamColumn', ele_tag_2, tower_node_tag_2, support_node_tag_2, \
                            sec_tag, trans_tag_2, *mass_0)
            
            skeleton['elements'][ele_tag_1] = {"eleType": "elasticBeamColumn", "eleNodesTags": [tower_node_tag_1, support_node_tag_1], \
                                                "vecxz": list(vector_z_1), "secTag": sec_tag, "cMass": "-cMass"}
            skeleton['elements'][ele_tag_2] = {"eleType": "elasticBeamColumn", "eleNodesTags": [tower_node_tag_2, support_node_tag_2], \
                                                "vecxz": list(vector_z_2), "secTag": sec_tag, "cMass": "-cMass"}
            
            # 建立支座单元
            ele_tag_1 = 50301102 + i * 1000
            ele_tag_2 = 50301202 + i * 1000

            mat_tag_list = boundary_tower[i]
            zero_ele_info = ['-mat', *mat_tag_list, '-dir', *dir_list]
            
            ops.element('zeroLength', ele_tag_1, support_node_tag_1, girder_node_tag_1, *zero_ele_info)
            if mat_tag_list[0] == 101:
                skeleton['equalDofs'][f'({support_node_tag_1}, {girder_node_tag_1})'] = [0, 2]
            else:
                skeleton['equalDofs'][f'({support_node_tag_1}, {girder_node_tag_1})'] = [2]

            ops.element('zeroLength', ele_tag_2, support_node_tag_2, girder_node_tag_2, *zero_ele_info)
            if mat_tag_list[0] == 101:
                skeleton['equalDofs'][f'({support_node_tag_2}, {girder_node_tag_2})'] = [0, 2]
            else:
                skeleton['equalDofs'][f'({support_node_tag_2}, {girder_node_tag_2})'] = [2]
            
        
        # 当主塔与加劲梁接触段为位于yz平面的平面结构时
        elif ops.nodeCoord(index_node_tag)[0] == tower_center_loc_list[i][0] and \
                ops.nodeCoord(index_node_tag)[1] != tower_center_loc_list[i][1]:
            
            # 建立辅助节点
            girder_node_tag_1 = 20200000 + girder_node_list[i] - (1 + insert_node_num)
            girder_node_tag_2 = 20300000 + girder_node_list[i] - (1 + insert_node_num)
            girder_node_tag_3 = 20200000 + girder_node_list[i] + (1 + insert_node_num)
            girder_node_tag_4 = 20300000 + girder_node_list[i] + (1 + insert_node_num)
            
            tower_node_tag_1 = 10101000 + i * 100000 + tower_node_list[i]
            tower_node_tag_2 = 10103000 + i * 100000 + tower_node_list[i]
            
            support_node_tag_1 = 50301101 + i * 1000
            support_node_tag_2 = 50301102 + i * 1000
            support_node_tag_3 = 50301301 + i * 1000
            support_node_tag_4 = 50301302 + i * 1000
            
            node_x = ops.nodeCoord(girder_node_tag_1)[0]
            node_y = ops.nodeCoord(girder_node_tag_1)[1]
            node_z = ops.nodeCoord(girder_node_tag_1)[2]
            
            ops.node(support_node_tag_1, node_x, node_y, node_z)
            ops.node(support_node_tag_2, -node_x, node_y, node_z)
            ops.node(support_node_tag_3, node_x, -node_y, node_z)
            ops.node(support_node_tag_4, -node_x, -node_y, node_z)
            
            skeleton['nodes'][support_node_tag_1] = {'crds':[node_x, node_y, node_z], 'mass':None}
            skeleton['nodes'][support_node_tag_2] = {'crds':[-node_x, node_y, node_z], 'mass':None}
            skeleton['nodes'][support_node_tag_3] = {'crds':[node_x, -node_y, node_z], 'mass':None}
            skeleton['nodes'][support_node_tag_4] = {'crds':[-node_x, -node_y, node_z], 'mass':None}
            
            # 建立刚臂单元
            # 建立刚臂单元坐标转换方式
            trans_tag_1 = i * 10 + 11
            trans_tag_2 = i * 10 + 12
            trans_tag_3 = i * 10 + 13
            trans_tag_4 = i * 10 + 14
            
            vector_x_1 = np.array([node_x - ops.nodeCoord(tower_node_tag_1)[0], \
                                   node_y - ops.nodeCoord(tower_node_tag_1)[1], \
                                   node_z - ops.nodeCoord(tower_node_tag_1)[2]])
            if vector_x_1[0] == 0 and vector_x_1[1] == 0:
                vector_z_1 = [1.0, 0.0, 0.0]
            else:
                vector_temp = np.array([0.0, 0.0, 1.0])
                vector_z_1 = np.cross(vector_x_1, vector_temp)
            ops.geomTransf('Linear', trans_tag_1, *vector_z_1)
            
            
            vector_x_2 = np.array([-node_x - ops.nodeCoord(tower_node_tag_1)[0], \
                                   node_y - ops.nodeCoord(tower_node_tag_1)[1], \
                                   node_z - ops.nodeCoord(tower_node_tag_1)[2]])
            if vector_x_2[0] == 0 and vector_x_2[1] == 0:
                vector_z_2 = [1.0, 0.0, 0.0]
            else:
                vector_temp = np.array([0.0, 0.0, 1.0])
                vector_z_2 = np.cross(vector_x_2, vector_temp)
            ops.geomTransf('Linear', trans_tag_2, *vector_z_2)
            
            vector_x_3 = np.array([node_x - ops.nodeCoord(tower_node_tag_2)[0], \
                                   -node_y - ops.nodeCoord(tower_node_tag_2)[1], \
                                   node_z - ops.nodeCoord(tower_node_tag_2)[2]])
            if vector_x_3[0] == 0 and vector_x_3[1] == 0:
                vector_z_3 = [1.0, 0.0, 0.0]
            else:
                vector_temp = np.array([0.0, 0.0, 1.0])
                vector_z_3 = np.cross(vector_x_3, vector_temp)
            ops.geomTransf('Linear', trans_tag_3, *vector_z_3)
            
            
            vector_x_4 = np.array([-node_x - ops.nodeCoord(tower_node_tag_2)[0], \
                                   -node_y - ops.nodeCoord(tower_node_tag_2)[1], \
                                   node_z - ops.nodeCoord(tower_node_tag_2)[2]])
            if vector_x_4[0] == 0 and vector_x_4[1] == 0:
                vector_z_4 = [1.0, 0.0, 0.0]
            else:
                vector_temp = np.array([0.0, 0.0, 1.0])
                vector_z_4 = np.cross(vector_x_4, vector_temp)
            ops.geomTransf('Linear', trans_tag_4, *vector_z_4)
            
            ele_tag_1 = 50301111 + i * 1000
            ele_tag_2 = 50301121 + i * 1000
            ele_tag_3 = 50301311 + i * 1000
            ele_tag_4 = 50301321 + i * 1000
            
            ops.element('elasticBeamColumn', ele_tag_1, tower_node_tag_1, support_node_tag_1, \
                            sec_tag, trans_tag_1, *mass_0)
            ops.element('elasticBeamColumn', ele_tag_2, tower_node_tag_1, support_node_tag_2, \
                            sec_tag, trans_tag_2, *mass_0)
            ops.element('elasticBeamColumn', ele_tag_3, tower_node_tag_2, support_node_tag_3, \
                            sec_tag, trans_tag_3, *mass_0)
            ops.element('elasticBeamColumn', ele_tag_4, tower_node_tag_2, support_node_tag_4, \
                            sec_tag, trans_tag_4, *mass_0)
            
            skeleton['elements'][ele_tag_1] = {"eleType": "elasticBeamColumn", "eleNodesTags": [tower_node_tag_1, support_node_tag_1], \
                                                "vecxz": list(vector_z_1), "secTag": sec_tag, "cMass": "-cMass"}
            skeleton['elements'][ele_tag_2] = {"eleType": "elasticBeamColumn", "eleNodesTags": [tower_node_tag_1, support_node_tag_2], \
                                                "vecxz": list(vector_z_2), "secTag": sec_tag, "cMass": "-cMass"}
            skeleton['elements'][ele_tag_3] = {"eleType": "elasticBeamColumn", "eleNodesTags": [tower_node_tag_2, support_node_tag_3], \
                                                "vecxz": list(vector_z_3), "secTag": sec_tag, "cMass": "-cMass"}
            skeleton['elements'][ele_tag_4] = {"eleType": "elasticBeamColumn", "eleNodesTags": [tower_node_tag_2, support_node_tag_4], \
                                                "vecxz": list(vector_z_4), "secTag": sec_tag, "cMass": "-cMass"}
            
            # 建立支座单元
            ele_tag_1 = 50301112 + i * 1000
            ele_tag_2 = 50301122 + i * 1000
            ele_tag_3 = 50301312 + i * 1000
            ele_tag_4 = 50301322 + i * 1000

            mat_tag_list = boundary_tower[i]
            zero_ele_info = ['-mat', *mat_tag_list, '-dir', *dir_list]
            
            ops.element('zeroLength', ele_tag_1, support_node_tag_1, girder_node_tag_1, *zero_ele_info)
            if mat_tag_list[0] == 101:
                skeleton['equalDofs'][f'({support_node_tag_1}, {girder_node_tag_1})'] = [0, 2]
            else:
                skeleton['equalDofs'][f'({support_node_tag_1}, {girder_node_tag_1})'] = [2]

            ops.element('zeroLength', ele_tag_2, support_node_tag_2, girder_node_tag_2, *zero_ele_info)
            if mat_tag_list[0] == 101:
                skeleton['equalDofs'][f'({support_node_tag_2}, {girder_node_tag_2})'] = [0, 2]
            else:
                skeleton['equalDofs'][f'({support_node_tag_2}, {girder_node_tag_2})'] = [2]

            ops.element('zeroLength', ele_tag_3, support_node_tag_3, girder_node_tag_3, *zero_ele_info)
            if mat_tag_list[0] == 101:
                skeleton['equalDofs'][f'({support_node_tag_3}, {girder_node_tag_3})'] = [0, 2]
            else:
                skeleton['equalDofs'][f'({support_node_tag_3}, {girder_node_tag_3})'] = [2]

            ops.element('zeroLength', ele_tag_4, support_node_tag_4, girder_node_tag_4, *zero_ele_info)
            if mat_tag_list[0] == 101:
                skeleton['equalDofs'][f'({support_node_tag_4}, {girder_node_tag_4})'] = [0, 2]
            else:
                skeleton['equalDofs'][f'({support_node_tag_4}, {girder_node_tag_4})'] = [2]
            
        
        # 当主塔与加劲梁接触段为一个竖向单支结构时
        elif ops.nodeCoord(index_node_tag)[0] == tower_center_loc_list[i][0] and \
                ops.nodeCoord(index_node_tag)[1] == tower_center_loc_list[i][1]:
            
            # 建立辅助节点
            girder_node_tag_1 = 20200000 + girder_node_list[i]
            girder_node_tag_2 = 20300000 + girder_node_list[i]
            
            tower_node_tag_1 = 10101000 + i * 100000 + tower_node_list[i]
            
            support_node_tag_1 = 50301111 + i * 1000
            support_node_tag_2 = 50301121 + i * 1000
            
            node_x = ops.nodeCoord(girder_node_tag_1)[0]
            node_y = ops.nodeCoord(girder_node_tag_1)[1]
            node_z = ops.nodeCoord(girder_node_tag_1)[2]
            
            ops.node(support_node_tag_1, node_x, node_y, node_z)
            ops.node(support_node_tag_2, -node_x, node_y, node_z)
            
            skeleton['nodes'][support_node_tag_1] = {'crds':[node_x, node_y, node_z], 'mass':None}
            skeleton['nodes'][support_node_tag_2] = {'crds':[-node_x, node_y, node_z], 'mass':None}
            
            # 建立刚臂单元
            # 建立刚臂单元坐标转换方式
            trans_tag_1 = i * 10 + 11
            trans_tag_2 = i * 10 + 12
            
            vector_x_1 = np.array([node_x - ops.nodeCoord(tower_node_tag_1)[0], \
                                   node_y - ops.nodeCoord(tower_node_tag_1)[1], \
                                   node_z - ops.nodeCoord(tower_node_tag_1)[2]])
            if vector_x_1[0] == 0 and vector_x_1[1] == 0:
                vector_z_1 = [1.0, 0.0, 0.0]
            else:
                vector_temp = np.array([0.0, 0.0, 1.0])
                vector_z_1 = np.cross(vector_x_1, vector_temp)
            ops.geomTransf('Linear', trans_tag_1, *vector_z_1)
            
            
            vector_x_2 = np.array([-node_x - ops.nodeCoord(tower_node_tag_1)[0], \
                                   node_y - ops.nodeCoord(tower_node_tag_1)[1], \
                                   node_z - ops.nodeCoord(tower_node_tag_1)[2]])
            if vector_x_2[0] == 0 and vector_x_2[1] == 0:
                vector_z_2 = [1.0, 0.0, 0.0]
            else:
                vector_temp = np.array([0.0, 0.0, 1.0])
                vector_z_2 = np.cross(vector_x_2, vector_temp)
            ops.geomTransf('Linear', trans_tag_2, *vector_z_2)
            
            ele_tag_1 = 50301111 + i * 1000
            ele_tag_2 = 50301121 + i * 1000
            
            ops.element('elasticBeamColumn', ele_tag_1, tower_node_tag_1, support_node_tag_1, \
                            sec_tag, trans_tag_1, *mass_0)
            ops.element('elasticBeamColumn', ele_tag_2, tower_node_tag_1, support_node_tag_2, \
                            sec_tag, trans_tag_2, *mass_0)
            
            skeleton['elements'][ele_tag_1] = {"eleType": "elasticBeamColumn", "eleNodesTags": [tower_node_tag_1, support_node_tag_1], \
                                                "vecxz": list(vector_z_1), "secTag": sec_tag, "cMass": "-cMass"}
            skeleton['elements'][ele_tag_2] = {"eleType": "elasticBeamColumn", "eleNodesTags": [tower_node_tag_1, support_node_tag_2], \
                                                "vecxz": list(vector_z_2), "secTag": sec_tag, "cMass": "-cMass"}
            
            # 建立支座单元
            ele_tag_1 = 50301112 + i * 1000
            ele_tag_2 = 50301122 + i * 1000

            mat_tag_list = boundary_tower[i]
            zero_ele_info = ['-mat', *mat_tag_list, '-dir', *dir_list]
            
            ops.element('zeroLength', ele_tag_1, support_node_tag_1, girder_node_tag_1, *zero_ele_info)
            if mat_tag_list[0] == 101:
                skeleton['equalDofs'][f'({support_node_tag_1}, {girder_node_tag_1})'] = [0, 2]
            else:
                skeleton['equalDofs'][f'({support_node_tag_1}, {girder_node_tag_1})'] = [2]

            ops.element('zeroLength', ele_tag_2, support_node_tag_2, girder_node_tag_2, *zero_ele_info)
            if mat_tag_list[0] == 101:
                skeleton['equalDofs'][f'({support_node_tag_2}, {girder_node_tag_2})'] = [0, 2]
            else:
                skeleton['equalDofs'][f'({support_node_tag_2}, {girder_node_tag_2})'] = [2]
        
        
        # 当主塔与加劲梁接触段为一个空间结构时
        else:
            
            # 建立辅助节点
            girder_node_tag_1 = 20200000 + girder_node_list[i] - (1 + insert_node_num)
            girder_node_tag_2 = 20300000 + girder_node_list[i] - (1 + insert_node_num)
            girder_node_tag_3 = 20200000 + girder_node_list[i] + (1 + insert_node_num)
            girder_node_tag_4 = 20300000 + girder_node_list[i] + (1 + insert_node_num)
            
            tower_node_tag_1 = 10101000 + i * 100000 + tower_node_list[i]
            tower_node_tag_2 = 10102000 + i * 100000 + tower_node_list[i]
            tower_node_tag_3 = 10103000 + i * 100000 + tower_node_list[i]
            tower_node_tag_4 = 10104000 + i * 100000 + tower_node_list[i]
            
            support_node_tag_1 = 50301101 + i * 1000
            support_node_tag_2 = 50301201 + i * 1000
            support_node_tag_3 = 50301301 + i * 1000
            support_node_tag_4 = 50301401 + i * 1000
            
            node_x = ops.nodeCoord(girder_node_tag_1)[0]
            node_y = ops.nodeCoord(girder_node_tag_1)[1]
            node_z = ops.nodeCoord(girder_node_tag_1)[2]
            
            ops.node(support_node_tag_1, node_x, node_y, node_z)
            ops.node(support_node_tag_2, -node_x, node_y, node_z)
            ops.node(support_node_tag_3, node_x, -node_y, node_z)
            ops.node(support_node_tag_4, -node_x, -node_y, node_z)
            
            skeleton['nodes'][support_node_tag_1] = {'crds':[node_x, node_y, node_z], 'mass':None}
            skeleton['nodes'][support_node_tag_2] = {'crds':[-node_x, node_y, node_z], 'mass':None}
            skeleton['nodes'][support_node_tag_3] = {'crds':[node_x, -node_y, node_z], 'mass':None}
            skeleton['nodes'][support_node_tag_4] = {'crds':[-node_x, -node_y, node_z], 'mass':None}
            
            # 建立刚臂单元
            # 建立刚臂单元坐标转换方式
            trans_tag_1 = i * 10 + 11
            trans_tag_2 = i * 10 + 12
            trans_tag_3 = i * 10 + 13
            trans_tag_4 = i * 10 + 14
            
            vector_x_1 = np.array([node_x - ops.nodeCoord(tower_node_tag_1)[0], \
                                   node_y - ops.nodeCoord(tower_node_tag_1)[1], \
                                   node_z - ops.nodeCoord(tower_node_tag_1)[2]])
            if vector_x_1[0] == 0 and vector_x_1[1] == 0:
                vector_z_1 = [1.0, 0.0, 0.0]
            else:
                vector_temp = np.array([0.0, 0.0, 1.0])
                vector_z_1 = np.cross(vector_x_1, vector_temp)
            ops.geomTransf('Linear', trans_tag_1, *vector_z_1)
            
            
            vector_x_2 = np.array([-node_x - ops.nodeCoord(tower_node_tag_2)[0], \
                                   node_y - ops.nodeCoord(tower_node_tag_2)[1], \
                                   node_z - ops.nodeCoord(tower_node_tag_2)[2]])
            if vector_x_2[0] == 0 and vector_x_2[1] == 0:
                vector_z_2 = [1.0, 0.0, 0.0]
            else:
                vector_temp = np.array([0.0, 0.0, 1.0])
                vector_z_2 = np.cross(vector_x_2, vector_temp)
            ops.geomTransf('Linear', trans_tag_2, *vector_z_2)
            
            vector_x_3 = np.array([node_x - ops.nodeCoord(tower_node_tag_4)[0], \
                                   -node_y - ops.nodeCoord(tower_node_tag_4)[1], \
                                   node_z - ops.nodeCoord(tower_node_tag_4)[2]])
            if vector_x_3[0] == 0 and vector_x_3[1] == 0:
                vector_z_3 = [1.0, 0.0, 0.0]
            else:
                vector_temp = np.array([0.0, 0.0, 1.0])
                vector_z_3 = np.cross(vector_x_3, vector_temp)
            ops.geomTransf('Linear', trans_tag_3, *vector_z_3)
            
            
            vector_x_4 = np.array([-node_x - ops.nodeCoord(tower_node_tag_3)[0], \
                                   -node_y - ops.nodeCoord(tower_node_tag_3)[1], \
                                   node_z - ops.nodeCoord(tower_node_tag_3)[2]])
            if vector_x_4[0] == 0 and vector_x_4[1] == 0:
                vector_z_4 = [1.0, 0.0, 0.0]
            else:
                vector_temp = np.array([0.0, 0.0, 1.0])
                vector_z_4 = np.cross(vector_x_4, vector_temp)
            ops.geomTransf('Linear', trans_tag_4, *vector_z_4)
            
            ele_tag_1 = 50301101 + i * 1000
            ele_tag_2 = 50301201 + i * 1000
            ele_tag_3 = 50301301 + i * 1000
            ele_tag_4 = 50301401 + i * 1000
            
            ops.element('elasticBeamColumn', ele_tag_1, tower_node_tag_1, support_node_tag_1, \
                            sec_tag, trans_tag_1, *mass_0)
            ops.element('elasticBeamColumn', ele_tag_2, tower_node_tag_2, support_node_tag_2, \
                            sec_tag, trans_tag_2, *mass_0)
            ops.element('elasticBeamColumn', ele_tag_3, tower_node_tag_4, support_node_tag_3, \
                            sec_tag, trans_tag_3, *mass_0)
            ops.element('elasticBeamColumn', ele_tag_4, tower_node_tag_3, support_node_tag_4, \
                            sec_tag, trans_tag_4, *mass_0)
            
            skeleton['elements'][ele_tag_1] = {"eleType": "elasticBeamColumn", "eleNodesTags": [tower_node_tag_1, support_node_tag_1], \
                                                "vecxz": list(vector_z_1), "secTag": sec_tag, "cMass": "-cMass"}
            skeleton['elements'][ele_tag_2] = {"eleType": "elasticBeamColumn", "eleNodesTags": [tower_node_tag_2, support_node_tag_2], \
                                                "vecxz": list(vector_z_2), "secTag": sec_tag, "cMass": "-cMass"}
            skeleton['elements'][ele_tag_3] = {"eleType": "elasticBeamColumn", "eleNodesTags": [tower_node_tag_4, support_node_tag_3], \
                                                "vecxz": list(vector_z_3), "secTag": sec_tag, "cMass": "-cMass"}
            skeleton['elements'][ele_tag_4] = {"eleType": "elasticBeamColumn", "eleNodesTags": [tower_node_tag_3, support_node_tag_4], \
                                                "vecxz": list(vector_z_4), "secTag": sec_tag, "cMass": "-cMass"}
            
            # 建立支座单元
            ele_tag_1 = 50301102 + i * 1000
            ele_tag_2 = 50301202 + i * 1000
            ele_tag_3 = 50301302 + i * 1000
            ele_tag_4 = 50301402 + i * 1000

            mat_tag_list = boundary_tower[i]
            zero_ele_info = ['-mat', *mat_tag_list, '-dir', *dir_list]
            
            ops.element('zeroLength', ele_tag_1, support_node_tag_1, girder_node_tag_1, *zero_ele_info)
            if mat_tag_list[0] == 101:
                skeleton['equalDofs'][f'({support_node_tag_1}, {girder_node_tag_1})'] = [0, 2]
            else:
                skeleton['equalDofs'][f'({support_node_tag_1}, {girder_node_tag_1})'] = [2]

            ops.element('zeroLength', ele_tag_2, support_node_tag_2, girder_node_tag_2, *zero_ele_info)
            if mat_tag_list[0] == 101:
                skeleton['equalDofs'][f'({support_node_tag_2}, {girder_node_tag_2})'] = [0, 2]
            else:
                skeleton['equalDofs'][f'({support_node_tag_2}, {girder_node_tag_2})'] = [2]

            ops.element('zeroLength', ele_tag_3, support_node_tag_3, girder_node_tag_3, *zero_ele_info)
            if mat_tag_list[0] == 101:
                skeleton['equalDofs'][f'({support_node_tag_3}, {girder_node_tag_3})'] = [0, 2]
            else:
                skeleton['equalDofs'][f'({support_node_tag_3}, {girder_node_tag_3})'] = [2]

            ops.element('zeroLength', ele_tag_4, support_node_tag_4, girder_node_tag_4, *zero_ele_info)
            if mat_tag_list[0] == 101:
                skeleton['equalDofs'][f'({support_node_tag_4}, {girder_node_tag_4})'] = [0, 2]
            else:
                skeleton['equalDofs'][f'({support_node_tag_4}, {girder_node_tag_4})'] = [2]




# 静力计算（重力分析）
def static_analysis(analyze_step_num=100):
    
    # 清除先前的分析设置
    ops.wipeAnalysis()
    
    # 创建系统方程
    ops.system('BandGeneral')

    # 创建约束处理方式
    ops.constraints('Transformation')

    # 创建自由度编号方式
    ops.numberer('RCM')

    # 创建收敛测试（残差范数阈值为1e-10，最大迭代次数为50）
    ops.test('NormDispIncr', 1.0e-10, 100, 3)

    # 创建求解算法（KrylovNewton算法）
    ops.algorithm('KrylovNewton')
#     ops.algorithm('RaphsonNewton')

    # 创建积分模式（步长为1/analyze_step_num的荷载控制模式）
    ops.integrator('LoadControl', 1/analyze_step_num)

    # 创建分析对象
    ops.analysis('Static')
    

    # 执行重力荷载分析，需要analyze_step_num步去达到荷载水平
    ops.analyze(int(analyze_step_num))

    # 将重力荷载设置为常量并重设域（domain）中的时间
    ops.loadConst('-time', 0.0)

    print("**重力分析完成**!")
    



# 斜拉桥建模
def cable_stayed_bridge_model(spans, width, \
                                skeleton, \
                                cable_plane_num, cable_num, \
                                tower_type, tower_h_ratio, tower_h_1, \
                                auxi_col_num, \
                                girder_type=-1, girder_mat=-1, \
                                bridge_year=-1, get_mode_num=10):
    
    # 根据观测数据进行斜拉桥有限元模型建模（采用国际标准单位）
    # 输入数据格式：
    # spans = 桥梁跨径布置 =  [跨1跨径，跨2跨径……]
    # width = 桥梁宽度
    # 
    # skeleton = 桥梁骨架信息
    # 
    # cable_plane_num = 斜拉索面数
    # cable_num = 单边单面斜拉索数
    # 
    # tower_type = 主塔形状（1为……）
    # tower_h_ratio = 主塔桥面上下高度比
    # tower_h_1 = 主塔桥面上部高度
    # 
    # auxi_col_num = 辅助墩数量
    # 
    # girder_type = 加劲梁截面类型（1为闭口箱梁，2为开口多梁，3为桁式梁）
    # girder_mat = 加劲梁材料类型（1为钢梁，2为钢筋混凝土梁，3为混合梁）
    #
    # bridge_year = 桥梁建造时间
    # 



    # 1-输入数据补全
    random_index = 0  # 随机噪声
    
    # 主梁估计
    if girder_type == 3:
        # 边箱式主梁
        # 1-1-加劲梁建模数据补全
        # 1-1-1-获取主跨和边跨信息
        if len(spans) == 2:
            main_span_len = 0
            main_span_num = 0
            side_span_len_1 = spans[0]
            side_span_len_2 = spans[-1]
        else:
            main_span_len = spans[1]
            main_span_num = len(spans) - 2
            side_span_len_1 = spans[0]
            side_span_len_2 = spans[-1]

        # 1-1-2-获取加劲梁高程定位信息
        tower_h_2 = tower_h_1 / tower_h_ratio
        girder_z = tower_h_2 + 10 * (tower_h_1 + tower_h_2) / 211
        
        # 1-1-3-获取加劲梁桥宽
        girder_width = width
        
        # 1-1-4-估算加劲梁截面参数（暂时取默认值，需另写函数进行估计）
        girder_sec_para_1 = [2.06711, 0.8335+0.0110, 211.559, 1.0818]
        girder_mat_para_1 = [16911.63788-900, 2e11, 7.7e10]
        girder_sec_para_2 = [1, 1/12, 1/12, 1/6]
        girder_mat_para_2 = [1, 4e12, 1.5e12]

        for i in range(4):
            girder_sec_para_1[i] = girder_sec_para_1[i] + \
                                    np.random.normal(0, 0.02*girder_sec_para_1[i]) * random_index
            
            if i < 3:
                girder_mat_para_1[i] = girder_mat_para_1[i] + \
                                        np.random.normal(0, 0.02*girder_mat_para_1[i]) * random_index
        
        # 1-1-5-加劲梁加密节点数量
        insert_node_num = 1

        # # 1-1-6-估计加密索间距（暂时取默认值，需另写函数进行估计）
        # densed_ratio_1 = 0.0303 * (1 + np.random.uniform(-0.1, 0.1) * random_index)  # 不宜取偏大值
        # densed_ratio_2 = 0.0303 * (1 + np.random.uniform(-0.1, 0.1) * random_index)  # 不宜取偏大值

        # # 1-1-7-估计无索区长度
        # no_anchor_len_middle = 100 / 920 * (1 + np.random.uniform(0, 5) * random_index)
        # no_anchor_len_tower = 1530 / 920 * (1 + np.random.uniform(-0.5, 0.1) * random_index)

        # 1-1-6-估计加密索间距（暂时取默认值，需另写函数进行估计）
        densed_ratio_1 = 0.2 * (1 + np.random.uniform(-0.1, 0.1) * random_index)  # 不宜取偏大值
        densed_ratio_2 = 0.2 * (1 + np.random.uniform(-0.1, 0.1) * random_index)  # 不宜取偏大值

        # 1-1-7-估计无索区长度
        no_anchor_len_middle = 1 * (1 + np.random.uniform(-0.1, 0.1) * random_index)
        no_anchor_len_tower = 1.5 * (1 + np.random.uniform(-0.1, 0.1) * random_index)

        side_random_value = np.random.uniform(0, 0.5)
        if side_random_value < 0.1:
            no_anchor_len_side_1 = 0
            no_anchor_len_side_2 = 0
        else:
            no_anchor_len_side_1 = 0 + side_random_value * random_index
            no_anchor_len_side_2 = 0 + side_random_value * random_index
    
    else:
        # 多工字梁等其他梁型
        # 1-1-加劲梁建模数据补全
        # 1-1-1-获取主跨和边跨信息
        if len(spans) == 2:
            main_span_len = 0
            main_span_num = 0
            side_span_len_1 = spans[0]
            side_span_len_2 = spans[-1]
        else:
            main_span_len = spans[1]
            main_span_num = len(spans) - 2
            side_span_len_1 = spans[0]
            side_span_len_2 = spans[-1]

        # 1-1-2-获取加劲梁高程定位信息
        tower_h_2 = tower_h_1 / tower_h_ratio
        girder_z = tower_h_2 + 10 * (tower_h_1 + tower_h_2) / 154
        
        # 1-1-3-获取加劲梁桥宽
        girder_width = width
        
        # 1-1-4-估算加劲梁截面参数（暂时取默认值，需另写函数进行估计）
        girder_sec_para_1 = [1.68359, 0.2213+0.0109, 151.591, 0.517903]
        girder_mat_para_1 = [14847.02501, 2e11, 7.7e10]
        girder_sec_para_2 = [1, 1/12, 1/12, 1/6]
        girder_mat_para_2 = [1, 4e12, 1.5e12]

        for i in range(4):
            girder_sec_para_1[i] = girder_sec_para_1[i] + \
                                    np.random.normal(0, 0.02*girder_sec_para_1[i]) * random_index
            
            if i < 3:
                girder_mat_para_1[i] = girder_mat_para_1[i] + \
                                        np.random.normal(0, 0.02*girder_mat_para_1[i]) * random_index
        
        # 1-1-5-加劲梁加密节点数量
        insert_node_num = 1

        # # 1-1-6-估计加密索间距（暂时取默认值，需另写函数进行估计）
        # densed_ratio_1 = 0.213 * (1 + np.random.uniform(-0.1, 0.1) * random_index)  # 不宜取偏大值
        # densed_ratio_2 = 0.213 * (1 + np.random.uniform(-0.1, 0.1) * random_index)  # 不宜取偏大值

        # # 1-1-7-估计无索区长度
        # no_anchor_len_middle = 1.7482 * (1 + np.random.uniform(-0.1, 0.1) * random_index)
        # no_anchor_len_tower = 22.5 / 9 * (1 + np.random.uniform(-0.1, 0.1) * random_index)

        # 1-1-6-估计加密索间距（暂时取默认值，需另写函数进行估计）
        densed_ratio_1 = 0.2 * (1 + np.random.uniform(-0.1, 0.1) * random_index)  # 不宜取偏大值
        densed_ratio_2 = 0.2 * (1 + np.random.uniform(-0.1, 0.1) * random_index)  # 不宜取偏大值

        # 1-1-7-估计无索区长度
        no_anchor_len_middle = 1 * (1 + np.random.uniform(-0.1, 0.1) * random_index)
        no_anchor_len_tower = 1.5 * (1 + np.random.uniform(-0.1, 0.1) * random_index)
        
        side_random_value = np.random.uniform(0, 0.5)
        if side_random_value < 0.1:
            no_anchor_len_side_1 = 0
            no_anchor_len_side_2 = 0
        else:
            no_anchor_len_side_1 = 0 + side_random_value * random_index
            no_anchor_len_side_2 = 0 + side_random_value * random_index
    

    # 主塔估计
    if tower_type == 2:
        # 1-2-主塔建模数据补全
        # 1-2-1-确定主塔中心点y坐标
        tower_center_loc_list = []
        if main_span_num == 0:
            tower_center_loc_list.append([0.0, 0.0, 0.0])
        else:
            for i in range(main_span_num+1):
                center_y = round(-main_span_num*main_span_len/2 + \
                            main_span_len*i, 2)
                tower_center_loc_list.append([0.0, center_y, 0.0])
        
        # 1-2-2-估计主塔截面参数（暂时取自适应默认值，需另写函数进行估计）
        key_node_para_1 = [
                                [[-12.8, 0.0, 0.0], 0, 0, -1],
                                [[-20.0, 0.0, 36.0], 1, 0, -1],
                                [[0.0, 0.0, 112.0], 0, 0, -1],
                                [[0.0, 0.0, 136.0], 0, 0, -1],
                                [[0.0, 0.0, 141.0], 0, 0, 1],
                                [[0.0, 0.0, 198.0], 0, 0, 0],
                                [[0.0, 0.0, 211.0], 1, 0, -1]
                            ]
        
        height_ratio = (tower_h_1 + tower_h_2) / 211  # 变换后主塔高度和原主塔高度的比值
        # width_ratio = girder_width / 30.35

        for i in range(len(key_node_para_1)):
            # key_node_para_1[i][0][1] = width_ratio * key_node_para_1[i][0][1]
            key_node_para_1[i][0][2] = height_ratio * key_node_para_1[i][0][2]

        # tower_angle_tan = - key_node_para_1[2][0][2] / key_node_para_1[0][0][0]
        for i in range(2):
            key_node_para_1[i][0][2] = tower_h_2 / 36.0 * key_node_para_1[i][0][2]
        # key_node_para_1[1][0][0] = key_node_para_1[0][0][0] + tower_h_2 / tower_angle_tan
        
        pylon_scale_ratio = 1 + np.random.normal(0, 0.02) * random_index  # 主塔截面参数调整系数

        col_sec_para = [
                            [45.4445, 415.6237, 801.4962, 1217.1199], [18.4100, 42.5903, 130.2247, 172,8150], \
                            [26.8000, 140.5583, 211.4773, 352.0356], [26.8000, 140.5583, 211.4773, 352.0356], \
                            [33.6800, 143.7645, 237.2305, 380.9950], [33.6800, 143.7645, 237.2305, 380.9950], \
                        ]
        
        for i in range(len(col_sec_para)):
            col_sec_para[i][0] = col_sec_para[i][0] * pylon_scale_ratio
            col_sec_para[i][1] = col_sec_para[i][1] * pylon_scale_ratio ** 2
            col_sec_para[i][2] = col_sec_para[i][2] * pylon_scale_ratio ** 2
            col_sec_para[i][3] = col_sec_para[i][1] + col_sec_para[i][2]
        
        col_mat_para = [
                            [2450, 3.35e10, 1.34e10], [2450, 3.35e10, 1.34e10], [2450, 3.35e11, 1.34e11], \
                            [2450, 3.35e10, 1.34e10], [2450, 3.35e10, 1.34e10], [2450, 3.35e10, 1.34e10], \
                        ]

        beam_sec_para = [[24.8000, 216.2667, 184.6507, 400.9174]]

        for i in range(len(beam_sec_para)):
            beam_sec_para[i][0] = beam_sec_para[i][0] * pylon_scale_ratio
            beam_sec_para[i][1] = beam_sec_para[i][1] * pylon_scale_ratio ** 2
            beam_sec_para[i][2] = beam_sec_para[i][2] * pylon_scale_ratio ** 2
            beam_sec_para[i][3] = beam_sec_para[i][1] + beam_sec_para[i][2]

        beam_mat_para = [[2500, 3.35e10, 1.34e10]]

        # 1-2-3-确定主塔划分单元数量
        tower_div_num = 20
        beam_div_num = 4

    else:
        # 其他类型桥塔
        # 1-2-主塔建模数据补全
        # 1-2-1-确定主塔中心点y坐标
        tower_center_loc_list = []
        if main_span_num == 0:
            tower_center_loc_list.append([0.0, 0.0, 0.0])
        else:
            for i in range(main_span_num+1):
                center_y = round(-main_span_num*main_span_len/2 + \
                            main_span_len*i, 2)
                tower_center_loc_list.append([0.0, center_y, 0.0])
        
        # 1-2-2-估计主塔截面参数（暂时取自适应默认值，需另写函数进行估计）
        key_node_para_1 = [
                                [[-12.5, 0.0, 0.0], 0, 0, -1],
                                [[-18.271, 0.0, 33.56], 1, 0, -1],
                                [[-18.9705, 0.0, 37.56], 0, 0, -1],
                                [[-12.5, 0.0, 92.56], 0, 0, -1],
                                [[-12.5, 0.0, 96.56], 1, 0, -1],
                                [[-12.5, 0.0, 102.56], 0, 0, 1],
                                [[-12.5, 0.0, 152.56], 0, 0, 0],
                                [[-12.5, 0.0, 154.00], 0, 0, -1]
                            ]
        
        height_ratio = (tower_h_1 + tower_h_2) / 154  # 变换后主塔高度和原主塔高度的比值
        # width_ratio = girder_width / 30.35

        for i in range(len(key_node_para_1)):
            # key_node_para_1[i][0][1] = width_ratio * key_node_para_1[i][0][1]
            key_node_para_1[i][0][2] = height_ratio * key_node_para_1[i][0][2]

        # tower_angle_tan = - key_node_para_1[2][0][2] / key_node_para_1[0][0][0]
        for i in range(3):
            key_node_para_1[i][0][2] = tower_h_2 / 37.56 * key_node_para_1[i][0][2]
        # key_node_para_1[1][0][0] = key_node_para_1[0][0][0] + tower_h_2 / tower_angle_tan
        
        pylon_scale_ratio = 1 + np.random.normal(0, 0.02) * random_index  # 主塔截面参数调整系数

        col_sec_para = [
                            [18.8794, 51.3746, 181.9950, 233.3696], [18.8794, 51.3746, 181.9950, 233.3696], \
                            [14.8255, 38.1699, 78.7960, 116.9659], [14.8255, 38.1699, 78.7960, 116.9659], \
                            [14.8255, 38.1699, 78.7960, 116.9659], [14.8255, 38.1699, 78.7960, 116.9659], \
                            [14.8255, 38.1699, 78.7960, 116.9659]
                        ]
        
        for i in range(len(col_sec_para)):
            col_sec_para[i][0] = col_sec_para[i][0] * pylon_scale_ratio
            col_sec_para[i][1] = col_sec_para[i][1] * pylon_scale_ratio ** 2
            col_sec_para[i][2] = col_sec_para[i][2] * pylon_scale_ratio ** 2
            col_sec_para[i][3] = col_sec_para[i][1] + col_sec_para[i][2]
        
        col_mat_para = [
                            [2500, 3.35e10, 1.34e10], [2500, 3.35e10, 1.34e10], \
                            [2500, 3.35e10, 1.34e10], [2500, 3.35e10, 1.34e10], \
                            [2500, 3.35e10, 1.34e10], [2500, 3.35e10, 1.34e10], \
                            [2500, 3.35e10, 1.34e10], \
                        ]

        beam_sec_para = [[19.0356, 163.5700, 132.8276, 296.3976], \
                            [18.6750, 158.2921, 118.0156, 276.3077]]

        for i in range(len(beam_sec_para)):
            beam_sec_para[i][0] = beam_sec_para[i][0] * pylon_scale_ratio
            beam_sec_para[i][1] = beam_sec_para[i][1] * pylon_scale_ratio ** 2
            beam_sec_para[i][2] = beam_sec_para[i][2] * pylon_scale_ratio ** 2
            beam_sec_para[i][3] = beam_sec_para[i][1] + beam_sec_para[i][2]

        beam_mat_para = [[2500, 3.35e10, 1.34e10], [2500, 3.35e10, 1.34e10]]

        # 1-2-3-确定主塔划分单元数量
        tower_div_num = 20
        beam_div_num = 4


    # 其他构件估计
    if girder_type == 3:
        # 边箱式主梁
        # 1-3-斜拉索建模数据补全（暂时取自适应默认值，需另写函数进行估计）
        if main_span_len != 0:
            span_ratio = main_span_len / 602
        else:
            span_ratio = max(side_span_len_1, side_span_len_2) / 301

        # cable_area_list_1_shore = [
        #                             0.011581, 0.011581, 0.01089, 0.009735, \
        #                             0.008581, 0.008581, 0.007196, 0.007196, \
        #                             0.007196, 0.007196, 0.007196, 0.006735, \
        #                             0.006735, 0.006735, 0.006735, 0.006735, \
        #                             0.006735, 0.006272, 0.006272, 0.005349, \
        #                             0.005349, 0.005349, 0.005349, 0.005349, \
        #                             0.004887, 0.004887, 0.004887, 0.004887, \
        #                             0.004887, 0.00581, 0.008581
        #                             ]

        # cable_area_list_1_river = [
        #                             0.011581, 0.011581, 0.008581, 0.008581,\
        #                             0.008581, 0.008581, 0.007196, 0.007196, \
        #                             0.007196, 0.007196, 0.006735, 0.006735, \
        #                             0.006735, 0.006272, 0.006272, 0.00581, \
        #                             0.00581, 0.00581, 0.006272, 0.005349, \
        #                             0.005349, 0.004887, 0.004887, 0.004887, \
        #                             0.004887, 0.004887, 0.004887, 0.004887, \
        #                             0.004887, 0.00581, 0.008581
        #                             ]
        
        cable_area_list_1_shore = [
                                    0.01304866, 0.01304866, 0.01184926, 0.0099909 , 0.0094139 , \
                                    0.0094139 , 0.0087214 , 0.0087214 , 0.0087214 , 0.0087214 , \
                                    0.0087214 , 0.0084909 , 0.0084909 , 0.00842686, 0.00797856, \
                                    0.00785048, 0.00810665, 0.00877174, 0.00979643, 0.00993266, \
                                    0.00993266, 0.00843833, 0.00754173, 0.0071219 , 0.00664185, \
                                    0.00625047, 0.00593026, 0.00593026, 0.00691225, 0.00866883, \
                                    0.01154866
                                    ]

        cable_area_list_1_river = [
                                    0.01304866, 0.01304866, 0.01069476, 0.0094139 , 0.0094139 , \
                                    0.0094139 , 0.0087214 , 0.0087214 , 0.0087214 , 0.0087214 , \
                                    0.0084909 , 0.0084909 , 0.0084909 , 0.00819536, 0.00774706, \
                                    0.00738798, 0.00731682, 0.00706777, 0.00726319, 0.00680169, \
                                    0.00680169, 0.00726804, 0.00731073, 0.0068909 , 0.00664185, \
                                    0.00625047, 0.00593026, 0.00593026, 0.00691225, 0.00866883, \
                                    0.01154866
                                    ]

        # 根据实桥尺寸和拉索数量放缩拉索面积数组
        cable_area_list_1_shore = list(np.array(cable_area_list_1_shore) * (31 / cable_num) * \
                                    span_ratio / (cable_plane_num / 2))
        cable_area_list_1_river = list(np.array(cable_area_list_1_river) * (31 / cable_num) * \
                                    span_ratio / (cable_plane_num / 2))
        
        # 获得插值拉索面积数组
        cable_area_list_1_shore = np.interp(np.linspace(0, len(cable_area_list_1_shore)-1, cable_num), \
                                            np.arange(len(cable_area_list_1_shore)), cable_area_list_1_shore)
        
        cable_area_list_1_river = np.interp(np.linspace(0, len(cable_area_list_1_river)-1, cable_num), \
                                            np.arange(len(cable_area_list_1_river)), cable_area_list_1_river)
        
        for i in range(len(cable_area_list_1_shore)):
            cable_area_list_1_shore[i] = cable_area_list_1_shore[i] * \
                                            (1 + np.random.uniform(-0.1, 0.1) * random_index)
            cable_area_list_1_river[i] = cable_area_list_1_river[i] * \
                                            (1 + np.random.uniform(-0.1, 0.1) * random_index)
        
        cable_area_list_1 = []
        invert_index = []  # 是否使用反转的拉索布置方式
        for i in range(main_span_num+1):
            cable_area_list_1.append(cable_area_list_1_shore)
            cable_area_list_1.append(cable_area_list_1_river)
            invert_index.append(0)


        # 1-4-斜拉桥墩建模数据补全
        # 1-4-1过渡墩（暂时取自适应默认值，需另写函数进行估计）
        col_sec_para_1 = [[8.5000, 32.6771, 19.2083, 51.8854], \
                            [8.5000, 32.6771, 19.2083, 51.8854]]
        col_mat_para_1 = [[2500, 3.35e10, 1.34e10], [2500, 3.35e10, 1.34e10]]
        col_h_1 = [tower_h_2, tower_h_2]
        col_div_num = 7

        # 1-4-2辅助墩
        col_loc_2 = None
        col_loc_3 = None
        col_sec_para_2 = None
        col_mat_para_2 = None
        col_sec_para_3 = None
        col_mat_para_3 = None
        col_h_2 = 0
        col_h_3 = 0
        if auxi_col_num != 0:
            col_loc_2 = list(np.linspace(0.0, 0.407, auxi_col_num+1))
            col_loc_2 = col_loc_2[1:]
            
            col_sec_para_2 = []
            col_mat_para_2 = []
            col_h_2 = []
            for i in range(int(auxi_col_num)):
                col_sec_para_2.append([6.1600, 13.8965, 16.8675, 30.764])
                col_mat_para_2.append([2500, 3.35e10, 1.34e10])
                col_h_2.append(tower_h_2)


            col_loc_3 = list(np.linspace(0.0, 0.407, auxi_col_num+1))
            col_loc_3 = col_loc_3[1:]
            
            col_sec_para_3 = []
            col_mat_para_3 = []
            col_h_3 = []
            for i in range(int(auxi_col_num)):
                col_sec_para_3.append([6.1600, 13.8965, 16.8675, 30.764])
                col_mat_para_3.append([2500, 3.35e10, 1.34e10])
                col_h_3.append(tower_h_2)


        # 1-5-边界条件建模数据补全
        boundary_tower = [[1, 0, 1, 0, 0, 0], [1, 0, 1, 0, 0, 0]]
        boundary_side = [[1, 0, 1, 0, 0, 0], [1, 0, 1, 0, 0, 0]]
        
        boundary_auxi_1 = []
        boundary_auxi_2 = []
        for i in range(int(auxi_col_num)):
            boundary_auxi_1.append([0, 0, 1, 0, 0, 0])
            boundary_auxi_2.append([0, 0, 1, 0, 0, 0])

    else:
        # 其他类型主梁
        # 1-3-斜拉索建模数据补全（暂时取自适应默认值，需另写函数进行估计）
        if main_span_len != 0:
            span_ratio = main_span_len / 423
        else:
            span_ratio = max(side_span_len_1, side_span_len_2) / 211.5

        # cable_area_list_1_shore = [
        #                             0.0102, 0.0102, 0.0072, 0.0072, 0.0072, \
        #                             0.0072, 0.0072, 0.0072, 0.0072, 0.0072, \
        #                             0.0063, 0.0063, 0.0081, 0.0102, 0.0102, \
        #                             0.0072, 0.0063, 0.0058, 0.0049, 0.0049, \
        #                             0.0072, 0.0102
        #                             ]

        # cable_area_list_1_river = [
        #                             0.0102, 0.0102, 0.0072, 0.0072, 0.0072, \
        #                             0.0072, 0.0072, 0.0072, 0.0072, 0.0072, \
        #                             0.0063, 0.0063, 0.0058, 0.0058, 0.0058, \
        #                             0.0072, 0.0063, 0.0058, 0.0049, 0.0049, \
        #                             0.0072, 0.0102
        #                             ]
        
        cable_area_list_1_shore = [
                                    0.01291959, 0.01241064, 0.01015493, 0.00932079, 0.00883104, \
                                    0.00863514, 0.00863514, 0.00863514, 0.00840692, 0.00835257, \
                                    0.00786341, 0.007954  , 0.00882992, 0.0097766 , 0.00983441, \
                                    0.00797441, 0.00711084, 0.00646543, 0.00596219, 0.0060105 , \
                                    0.00783771, 0.01143443
                                    ]

        cable_area_list_1_river = [
                                    0.01291959, 0.01192075, 0.00950196, 0.00932079, 0.00883104, \
                                    0.00863514, 0.00863514, 0.00840692, 0.00840692, 0.0081561 , \
                                    0.00756885, 0.00726458, 0.0070255 , 0.00693024, 0.00673441, \
                                    0.00721427, 0.00688212, 0.00646543, 0.00596219, 0.0060105 , \
                                    0.00783771, 0.01143443
                                    ]

        # 根据实桥尺寸和拉索数量放缩拉索面积数组
        cable_area_list_1_shore = list(np.array(cable_area_list_1_shore) * (22 / cable_num) * \
                                    span_ratio / (cable_plane_num / 2))
        cable_area_list_1_river = list(np.array(cable_area_list_1_river) * (22 / cable_num) * \
                                    span_ratio / (cable_plane_num / 2))
        
        # 获得插值拉索面积数组
        cable_area_list_1_shore = np.interp(np.linspace(0, len(cable_area_list_1_shore)-1, cable_num), \
                                            np.arange(len(cable_area_list_1_shore)), cable_area_list_1_shore)
        
        cable_area_list_1_river = np.interp(np.linspace(0, len(cable_area_list_1_river)-1, cable_num), \
                                            np.arange(len(cable_area_list_1_river)), cable_area_list_1_river)
        
        for i in range(len(cable_area_list_1_shore)):
            cable_area_list_1_shore[i] = cable_area_list_1_shore[i] * \
                                            (1 + np.random.uniform(-0.1, 0.1) * random_index)
            cable_area_list_1_river[i] = cable_area_list_1_river[i] * \
                                            (1 + np.random.uniform(-0.1, 0.1) * random_index)
        
        cable_area_list_1 = []
        invert_index = []  # 是否使用反转的拉索布置方式
        for i in range(main_span_num+1):
            cable_area_list_1.append(cable_area_list_1_shore)
            cable_area_list_1.append(cable_area_list_1_river)
            invert_index.append(0)


        # 1-4-斜拉桥墩建模数据补全
        # 1-4-1过渡墩（暂时取自适应默认值，需另写函数进行估计）
        col_sec_para_1 = [[6.0800, 1.2971, 7.3163, 8.6134], \
                            [6.0800, 1.2971, 7.3163, 8.6134]]
        col_mat_para_1 = [[2500, 3.35e10, 1.34e10], [2500, 3.35e10, 1.34e10]]
        col_h_1 = [tower_h_2, tower_h_2]
        col_div_num = 7

        # 1-4-2辅助墩
        col_loc_2 = None
        col_loc_3 = None
        col_sec_para_2 = None
        col_mat_para_2 = None
        col_sec_para_3 = None
        col_mat_para_3 = None
        col_h_2 = 0
        col_h_3 = 0
        if auxi_col_num != 0:
            col_loc_2 = list(np.linspace(0.0, 0.407, auxi_col_num+1))
            col_loc_2 = col_loc_2[1:]
            
            col_sec_para_2 = []
            col_mat_para_2 = []
            col_h_2 = []
            for i in range(int(auxi_col_num)):
                col_sec_para_2.append([4.3800, 5.0748, 6.2639, 11.3387])
                col_mat_para_2.append([2500, 3.35e10, 1.34e10])
                col_h_2.append(tower_h_2)


            col_loc_3 = list(np.linspace(0.0, 0.407, auxi_col_num+1))
            col_loc_3 = col_loc_3[1:]
            
            col_sec_para_3 = []
            col_mat_para_3 = []
            col_h_3 = []
            for i in range(int(auxi_col_num)):
                col_sec_para_3.append([4.3800, 5.0748, 6.2639, 11.3387])
                col_mat_para_3.append([2500, 3.35e10, 1.34e10])
                col_h_3.append(tower_h_2)


        # 1-5-边界条件建模数据补全
        boundary_tower = [[1, 0, 1, 0, 0, 0], [1, 0, 1, 0, 0, 0]]
        boundary_side = [[1, 0, 1, 0, 0, 0], [1, 0, 1, 0, 0, 0]]
        
        boundary_auxi_1 = []
        boundary_auxi_2 = []
        for i in range(int(auxi_col_num)):
            boundary_auxi_1.append([0, 0, 1, 0, 0, 0])
            boundary_auxi_2.append([0, 0, 1, 0, 0, 0])
    

    # 2-全桥建模
    ops.wipe()  # 清除既有模型
    ops.model('basic', '-ndm', 3, '-ndf', 6)  # 定义模型为3维模型，单节点具有6个自由度

    # 2-1加劲梁建模
    girder_div_num_list, girder_G_list = \
                stiffening_girder_modelling(main_span_len, main_span_num, side_span_len_1, side_span_len_2, \
                                                cable_num, girder_z, girder_width, \
                                                girder_sec_para_1, girder_mat_para_1, \
                                                girder_sec_para_2, girder_mat_para_2, \
                                                skeleton, \
                                                no_anchor_len_tower=no_anchor_len_tower, \
                                                no_anchor_len_middle=no_anchor_len_middle, \
                                                no_anchor_len_side_1=no_anchor_len_side_1, \
                                                no_anchor_len_side_2=no_anchor_len_side_2, \
                                                insert_node_num=insert_node_num, \
                                                densed_ratio_1=densed_ratio_1, densed_ratio_2=densed_ratio_2)

    # 2-2主塔建模
    anchor_nodes_range_list = []
    no_anchor_nodes_list = []
    for i in range(main_span_num+1):
        (key_nodes, beam_nodes_1, beam_nodes_2, anchor_nodes_range, no_anchor_nodes) = \
                                towers_modelling(i+1, tower_center_loc_list[i], key_node_para_1, cable_num, \
                                                    col_sec_para, col_mat_para, tower_div_num, \
                                                    skeleton, \
                                                    beam_sec_para_1=beam_sec_para, beam_mat_para_1=beam_mat_para, \
                                                    beam_div_num_1=beam_div_num)
        anchor_nodes_range_list.append(anchor_nodes_range)
        no_anchor_nodes_list.append(no_anchor_nodes)

    # 2-3斜拉索建模
    origin_cable_f_list = \
                cables_modelling(anchor_nodes_range_list, no_anchor_nodes_list, tower_center_loc_list, \
                                    girder_div_num_list, insert_node_num, cable_num, \
                                    cable_area_list_1, girder_G_list, \
                                    cable_plane_num, invert_index, \
                                    skeleton)


    # 计算加劲梁纵梁总节点数
    girder_ele_num_0 = girder_div_num_list[2] +  girder_div_num_list[3] + \
                         girder_div_num_list[4] * len(anchor_nodes_range_list) * 2 + \
                         girder_div_num_list[5] * (len(anchor_nodes_range_list) - 1) + \
                        (cable_num - 1) * (len(anchor_nodes_range_list) * 2)
    lo_node_num = int(girder_ele_num_0 * (insert_node_num + 1) + 1)

    # 2-4过渡墩和辅助墩建模
    if main_span_num == 0:
        if side_span_len_1 < side_span_len_2:
            auxi_col_node_list_1, auxi_col_node_list_2 = \
                        column_modelling(main_span_len, main_span_num, side_span_len_1, side_span_len_2, \
                                            girder_width, lo_node_num, insert_node_num, \
                                            col_sec_para_1, col_mat_para_1, col_h_1, \
                                            col_div_num, \
                                            skeleton, \
                                            col_loc_2=col_loc_2, \
                                            col_sec_para_2=col_sec_para_2, \
                                            col_mat_para_2=col_mat_para_2, col_h_2=col_h_2)
        else:
            auxi_col_node_list_1, auxi_col_node_list_2 = \
                        column_modelling(main_span_len, main_span_num, side_span_len_1, side_span_len_2, \
                                            girder_width, lo_node_num, insert_node_num, \
                                            col_sec_para_1, col_mat_para_1, col_h_1, \
                                            col_div_num, \
                                            skeleton, \
                                            col_loc_3=col_loc_3, \
                                            col_sec_para_3=col_sec_para_3, \
                                            col_mat_para_3=col_mat_para_3, col_h_3=col_h_3)
    
    else:
        auxi_col_node_list_1, auxi_col_node_list_2 = \
                        column_modelling(main_span_len, main_span_num, side_span_len_1, side_span_len_2, \
                                            girder_width, lo_node_num, insert_node_num, \
                                            col_sec_para_1, col_mat_para_1, col_h_1, \
                                            col_div_num, \
                                            skeleton, \
                                            col_loc_2=col_loc_2, col_loc_3=col_loc_3, \
                                            col_sec_para_2=col_sec_para_2, \
                                            col_mat_para_2=col_mat_para_2, col_h_2=col_h_2, \
                                            col_sec_para_3=col_sec_para_3, \
                                            col_mat_para_3=col_mat_para_3, col_h_3=col_h_3)


    # 计算边界条件相关节点编号（仅对默认桥塔适用）
    tower_node_list = []
    girder_node_list = []
    side_span_node_num = (girder_div_num_list[2] + cable_num - 1 + girder_div_num_list[4]) * \
                            (insert_node_num + 1) + 1
    main_span_node_num = (girder_div_num_list[5] + (cable_num - 1) * 2 + girder_div_num_list[4] * 2) * \
                            (insert_node_num + 1) + 1

    for i in range(main_span_num+1):
        tower_node_list.append(int(key_nodes[1]))
        girder_node_list.append(int(side_span_node_num + (main_span_node_num-1) * i))

    # 2-5边界条件建模
    boundary_modelling(tower_node_list, tower_center_loc_list, \
                        girder_node_list, lo_node_num, insert_node_num, col_div_num, \
                        boundary_tower, boundary_side, \
                        skeleton, \
                        auxi_col_node_list_1, auxi_col_node_list_2, \
                        boundary_auxi_1, boundary_auxi_2)


    # 3-模态分析
    # eig_vals = ops.eigen('-fullGenLapack', get_mode_num)

    eig_vals = ops.eigen(get_mode_num)

    for i in range(get_mode_num):
        eig_vals[i] = np.sqrt(eig_vals[i]) / (2 * np.pi)  # 计算固有频率

    # print(eig_vals)

    # eig_vals = []

    return eig_vals, skeleton




# 斜拉桥阻尼比计算
def cable_stayed_bridge_damping_ratio(eig_vals, v_eig_vals, girder_type):
    
    if girder_type == 3:
        xi_0 = 0.01  # 阻尼比

        omega_1 = 1 / (1 /eig_vals[1] * 1) * (2 * np.pi)
        omega_2 = 1 / (1 /eig_vals[14] * 1) * (2 * np.pi)
    else:
        xi_0 = 0.013  # 阻尼比

        omega_1 = 1 / (1 /eig_vals[1] * 1) * (2 * np.pi)
        omega_2 = 1 / (1 /eig_vals[14] * 1) * (2 * np.pi)

    alpha = 2 * omega_1 * omega_2 * (omega_1 - omega_2) * xi_0 / \
            (omega_1 ** 2 - omega_2 ** 2)

    beta = 2 * (omega_1 - omega_2) * xi_0 / \
            (omega_1 ** 2 - omega_2 ** 2)

    zeta_list = []

    for i in range(len(v_eig_vals)):
        omega = v_eig_vals[i] * (2 * np.pi)
        
        zeta = alpha / (2 * omega) + beta * omega / 2
        zeta_list.append(zeta)

    # zeta_list_test = []

    # for i in range(20):
    #     omega = eig_vals[i] * (2 * np.pi)
        
    #     zeta = alpha / (2 * omega) + beta * omega / 2
    #     zeta_list_test.append(zeta)
    #     if i < 10:
    #         print(eig_vals[i], zeta)
    
    return zeta_list




# 斜拉桥模态质量计算 与 加劲梁含竖向位移振型阶数判断
def cable_stayed_bridge_modal_mass(eig_vals, get_mode_num):

    # 1-提取质量矩阵
    ops.wipeAnalysis()
    ops.system("BandSPD")
    ops.numberer("RCM")
    ops.constraints("Plain")
    ops.algorithm("Linear")
    ops.integrator('Newmark', 0.5, 0.25)
    ops.system('FullGeneral')
    ops.analysis('Transient')
    
    # 设置为输出质量矩阵的模式
    ops.integrator('GimmeMCK', 1.0, 0.0, 0.0)
    ops.analyze(1, 0.0)
    N = ops.systemSize()  # 质量矩阵维数

    M = ops.printA('-ret')
    M = np.array(M)
    M.shape = (N, N)

    # 只保留对角线元素
    # for i in range(N):
    #     for j in range(N):
    #         if i != j:
    #             M[i][j] = 0
    # print(np.sum(M/1000))

    # 绘制质量矩阵
    # plt.imshow(M)
    # plt.colorbar()
    # plt.show()
    # plt.close()

    
    # 2-计算模态质量（振型最大值归一化）
    modal_mass_list_0 = []
    modal_mass_list_1 = []
    modal_eff_mass_list = []

    for mode_num in range(get_mode_num):
        obs_mode_num = mode_num + 1

        node_tag_list = ops.getNodeTags()
        mode_shape_array = np.zeros([1, M.shape[0]])
        r_array = np.zeros([1, M.shape[0]])

        for i in range(len(node_tag_list)):
            node_tag = node_tag_list[i]
            for j in range(6):
                if ops.nodeDOFs(node_tag)[j] >= 0:
                    dof_tag = ops.nodeDOFs(node_tag)[j]

                    eig_val = ops.nodeEigenvector(node_tag, obs_mode_num, j+1)
                    mode_shape_array[0][dof_tag] = eig_val
                    if j >= 3:
                        # 忽略转动自由度的质量
                        mode_shape_array[0][dof_tag] = 0
                    if j == 2:
                        r_array[0][dof_tag] = 1

        # mode_shape_array = mode_shape_array / np.linalg.norm(mode_shape_array)  # L2范数归一化振型
        mode_shape_array = mode_shape_array / np.max(abs(mode_shape_array))  # 最大振型分量归一化振型
        
        modal_mass = (mode_shape_array @ M @ mode_shape_array.T)[0][0]  # 模态质量计算
        modal_eff_mass = (abs(mode_shape_array) @ M @ r_array.T)[0][0] ** 2 / \
                                    modal_mass  # 模态有效质量计算（分子的绝对值是为了将扭转纳入考虑）

        # print(modal_mass)
        # print(modal_eff_mass)

        modal_mass_list_0.append(round(modal_mass/1000, 2))
        modal_eff_mass_list.append(modal_eff_mass)


    # 3-选取前三阶竖弯（扭转）振型
    v_eig_vals = []
    v_eig_num_list = []
    max_model_eff_mass = max(modal_eff_mass_list)

    for i in range(get_mode_num):
        if len(v_eig_vals) >= 3:
            break
        
        if modal_eff_mass_list[i] / max_model_eff_mass > 0.01 and i > 0:
            # 判断当前振型是否为竖向位移明显的振型
            v_eig_vals.append(eig_vals[i])
            v_eig_num_list.append(i)

            modal_mass_list_1.append(modal_mass_list_0[i])

    return modal_mass_list_1, v_eig_vals, v_eig_num_list




# 斜拉桥结果输出
def cable_stayed_bridge_output(bridge_name, eig_vals, zeta_list, modal_mass_list):

    bridge_output_data = pd.DataFrame({'振型阶数':[1, 2, 3], \
                                   '固有频率(Hz)': eig_vals[0:3], \
                                   '振型阻尼比': [100*zeta for zeta in zeta_list], \
                                   '模态质量(t)': modal_mass_list[0:3]})

    # bridge_output_data.to_csv(f'{bridge_name}输出数据.csv', index=False, encoding='utf-8-sig')

    return bridge_output_data




# 斜拉桥图片输出
def cable_stayed_bridge_pic_output(bridge_ID, v_eig_vals, v_eig_num_list, eig_vals):
    
    pic_info_list = []  # 存储输出四张图片的信息（[{"name": "桥型图/第x阶振型图", "path": "xxx.png"}]）

    # 1-点、线参数定义
    kwargs_1_1 = {'marker': '.', 'color': 'b', 's': 10, 'alpha': 1}
    kwargs_1_2 = {'marker': '.', 'color': 'black', 's': 10, 'alpha': 0.1}

    kwargs_2_1 = {'color': 'black', 'linewidth': 1, 'alpha': 1}
    kwargs_2_2 = {'color': 'black', 'linewidth': 1, 'alpha': 0.1} 


    # 2-绘制桥型图
    plt.close()
        
    fig = plt.figure()
    fig.set_size_inches(30, 30)
    # fig.set_facecolor('#F4F4F4')

    ax_0 = fig.add_subplot(projection='3d')
    
    node_loc_dict_0 = {}

    node_tags_list = ops.getNodeTags()

    for i in range(len(node_tags_list)):
        node_tag = node_tags_list[i]
        x_1 = ops.nodeCoord(node_tag)[0]
        y_1 = ops.nodeCoord(node_tag)[1]
        z_1 = ops.nodeCoord(node_tag)[2]
        node_loc_dict_0[node_tag] = [x_1, y_1, z_1]
        ax_0.scatter(x_1, y_1, z_1, **kwargs_1_1)

    ele_tag_list = ops.getEleTags()

    line_x_list_0 = []
    line_y_list_0 = []
    line_z_list_0 = []

    for i in range(len(ele_tag_list)):
        line_x_list = []
        line_y_list = []
        line_z_list = []

        line_x_list.append(node_loc_dict_0[(ops.eleNodes(ele_tag_list[i])[0])][0])
        line_x_list.append(node_loc_dict_0[(ops.eleNodes(ele_tag_list[i])[1])][0])

        line_y_list.append(node_loc_dict_0[(ops.eleNodes(ele_tag_list[i])[0])][1])
        line_y_list.append(node_loc_dict_0[(ops.eleNodes(ele_tag_list[i])[1])][1])

        line_z_list.append(node_loc_dict_0[(ops.eleNodes(ele_tag_list[i])[0])][2])
        line_z_list.append(node_loc_dict_0[(ops.eleNodes(ele_tag_list[i])[1])][2])
        
        if ops.nodeCoord(ops.eleNodes(ele_tag_list[i])[0]) != ops.nodeCoord(ops.eleNodes(ele_tag_list[i])[1]):
            ax_0.plot3D(line_x_list, line_y_list, line_z_list, **kwargs_2_1)
            line_x_list_0.append(line_x_list)
            line_y_list_0.append(line_y_list)
            line_z_list_0.append(line_z_list)

    # 绘图参数设置
    ax_0.xaxis._axinfo['grid'].update({'linestyle': '--',  'linewidth': 0.3})
    ax_0.yaxis._axinfo['grid'].update({'linestyle': '--', 'linewidth': 0.3})
    ax_0.zaxis._axinfo['grid'].update({'linestyle': '--', 'linewidth': 0.3})
    ax_0.axis('off')

    ax_0.set_aspect('equal')

    ax_0.view_init(0, 0)  # 侧视
    # ax_0.view_init(30, -50)  # 透视
    # ax_0.view_init(10, 45)
    # ax_0.view_init(0, 90)  # 正视
    # ax_0.view_init(90, 0)  # 俯视
    
    # ax_0.set_title(f'桥型图', \
    #             fontdict={'family': 'STSONG', 'size': 30})
    
    # ax_0.set(facecolor='#F4F4F4')

    # plt.savefig(f'C:\\Users\LZR\\Python_Files\\参数化建模\\梁桥\\模块化\\桥型图.png', dpi=300)
    
    plt.savefig(f'{bridge_ID}_0.png', dpi=100, \
                    bbox_inches='tight', pad_inches=0.05)
    pic_info_list.append({"name": f"桥型图", "path": f"{bridge_ID}_0.png"})
    
    # print(f'桥型图输出')
    
    # plt.show()
    ax_0.remove()
    plt.close('all')


    # 3-绘制3阶振型图片
    plt.close() 
    for k in range(3):
        
        fig = plt.figure()
        fig.set_size_inches(30, 30)
        # fig.set_facecolor('#F4F4F4')

        ax_0 = fig.add_subplot(projection='3d')

        node_loc_dict_1 = {}

        scaler = 60000

        obs_mode_num = v_eig_num_list[k] + 1
        # obs_mode_num = k + 1

        # for i in range(len(node_tags_list)):
        #     node_tag = node_tags_list[i]
        #     x_1 = node_loc_dict_0[node_tag][0]
        #     y_1 = node_loc_dict_0[node_tag][1]
        #     z_1 = node_loc_dict_0[node_tag][2]
        #     ax_0.scatter(x_1, y_1, z_1, **kwargs_1_2)

        for i in range(len(node_tags_list)):
            node_tag = node_tags_list[i]
            x_1 = node_loc_dict_0[node_tag][0] + scaler * ops.nodeEigenvector(node_tag, obs_mode_num, 1)
            y_1 = node_loc_dict_0[node_tag][1] + scaler * ops.nodeEigenvector(node_tag, obs_mode_num, 2)
            z_1 = node_loc_dict_0[node_tag][2] + scaler * ops.nodeEigenvector(node_tag, obs_mode_num, 3)
            node_loc_dict_1[node_tag] = [x_1, y_1, z_1]
            # ax_0.scatter(x_1, y_1, z_1, **kwargs_1_1)

        ele_tag_list = ops.getEleTags()

        for i in range(len(line_x_list_0)):
            ax_0.plot3D(line_x_list_0[i], line_y_list_0[i], line_z_list_0[i], **kwargs_2_2)

        for i in range(len(ele_tag_list)):
            line_x_list = []
            line_y_list = []
            line_z_list = []

            line_x_list.append(node_loc_dict_1[(ops.eleNodes(ele_tag_list[i])[0])][0])
            line_x_list.append(node_loc_dict_1[(ops.eleNodes(ele_tag_list[i])[1])][0])

            line_y_list.append(node_loc_dict_1[(ops.eleNodes(ele_tag_list[i])[0])][1])
            line_y_list.append(node_loc_dict_1[(ops.eleNodes(ele_tag_list[i])[1])][1])

            line_z_list.append(node_loc_dict_1[(ops.eleNodes(ele_tag_list[i])[0])][2])
            line_z_list.append(node_loc_dict_1[(ops.eleNodes(ele_tag_list[i])[1])][2])

            if ops.nodeCoord(ops.eleNodes(ele_tag_list[i])[0]) != ops.nodeCoord(ops.eleNodes(ele_tag_list[i])[1]):
                ax_0.plot3D(line_x_list, line_y_list, line_z_list, **kwargs_2_1)

        # 绘图参数设置
        ax_0.xaxis._axinfo['grid'].update({'linestyle': '--',  'linewidth': 0.3})
        ax_0.yaxis._axinfo['grid'].update({'linestyle': '--', 'linewidth': 0.3})
        ax_0.zaxis._axinfo['grid'].update({'linestyle': '--', 'linewidth': 0.3})
        ax_0.axis('off')

        ax_0.set_aspect('equal')

        ax_0.view_init(0, 0)  # 侧视
        # ax_0.view_init(30, -50)  # 透视
        # ax_0.view_init(10, 45)
        # ax_0.view_init(0, 90)  # 正视
        # ax_0.view_init(90, 0)  # 俯视
        
        # ax_0.set_title(f'第{k+1}阶振型-{round(v_eig_vals[k],3)}Hz', \
        #             fontdict={'family': 'STSONG', 'size': 30})
        
        # ax_0.set_title(f'第{k+1}阶振型-{round(eig_vals[k],3)}Hz', \
        #             fontdict={'family': 'STSONG', 'size': 30})
        
        # ax_0.set(facecolor='#F4F4F4')

        # plt.savefig(f'C:\\Users\LZR\\Python_Files\\参数化建模\\梁桥\\模块化\\第{obs_mode_num}阶振型-透视图.png', dpi=300)

        plt.savefig(f'{bridge_ID}_{k+1}.png', dpi=100, \
                    bbox_inches='tight', pad_inches=0.05)
        pic_info_list.append({"name": f"第{k+1}阶振型图", "path": f"{bridge_ID}_{k+1}.png"})
        
        # print(f'第{k+1}阶振型图输出')
        
        # plt.show()
        ax_0.remove()
        plt.close('all')

    return pic_info_list




# 斜拉桥skeleton的json文件输出
def cable_stayed_bridge_skeleton_output(bridge_skeleton, bridge_ID, bridge_name, skeleton_path):

    # 获取当前时间
    now = datetime.now()
    analysis_moment = now.isoformat(sep="T", timespec="seconds")

    # 提取桥梁位置字符串
    # bridge_address = bridge_ID.split("_", 1)[1]
    bridge_address = bridge_ID.replace("bridge_", "", 1)  # 正式测试时，提取地址可用该方法

    bridge_data_dict = {
                            "unionId": bridge_ID,
                            "dataTime": analysis_moment,
                            "bridgeName": bridge_name,
                            "bridgeAddress": bridge_address,
                            "skeleton": bridge_skeleton,
                        }

    file_path = f'{skeleton_path}.json'
    with open(file_path, 'w', encoding='utf-8') as json_file:
        json.dump(bridge_data_dict, json_file, ensure_ascii=False, indent=4)

    return analysis_moment, bridge_address




# 斜拉桥参数输入与分析代码执行
def cable_stayed_bridge_input(spans, width, \
                                cable_plane_num, cable_num, \
                                tower_type_along, tower_type_cross, \
                                tower_h_ratio, tower_h_1, \
                                auxi_col_num, \
                                bridge_ID, image_path, skeleton_path, \
                                girder_type=-1, girder_mat=-1, \
                                bridge_year=-1, bridge_name='某斜拉桥'):
    
    # 输入数据格式：
    # spans = 桥梁跨径布置 =  [跨1跨径，跨2跨径……]
    # width = 桥梁宽度
    # 
    # cable_plane_num = 斜拉索面数
    # cable_num = 单组斜拉索数
    # 
    # tower_type_along = 顺桥向主塔形状（1为“1字型”桥塔，2为“倒Y型”桥塔，3为“A字型”桥塔）
    # tower_type_cross = 横桥向主塔形状（1为“1字型”桥塔，2为“倒Y型”桥塔，3为“A字型”桥塔，4为“门型”桥塔）
    # 
    # tower_h_ratio = 主塔桥面上下高度比
    # tower_h_1 = 主塔桥面上部高度
    # 
    # auxi_col_num = 辅助墩数量
    # 
    # bridge_ID = 桥梁ID（桥梁唯一标识）
    # image_path = 保存图片的路径
    # skeleton_path = 保存skeleton文件的路径
    # 
    # girder_type = 加劲梁截面类型（1为板式，2为多工字钢式，3为边箱式，4为分体箱式，5为整体箱式，6为桁架式）
    # girder_mat = 加劲梁材料类型（1为混凝土，2为钢，3为混合式）
    #
    # bridge_year = 桥梁建造时间
    # bridge_name = 桥梁名称
    # 


    # 1-建模
    get_mode_num = 20  # 计算模态的阶数

    bridge_skeleton = {
                        'ndm':3, 'ndf':6, \
                        'nodes':{}, \
                        'materials':{}, \
                        'sections':{}, \
                        'elements':{}, \
                        'spDofs':{}, \
                        'equalDofs':{}, \
                        'rigidDiaphragms':{}, \
                        'loads':{}, \
                        }  # 桥梁骨架信息（后续补充其使用方法）

    eig_vals, bridge_skeleton = cable_stayed_bridge_model(spans, width, \
                                                            bridge_skeleton, \
                                                            cable_plane_num, cable_num, \
                                                            tower_type_cross, tower_h_ratio, tower_h_1, \
                                                            auxi_col_num, \
                                                            girder_type, girder_mat, \
                                                            bridge_year, get_mode_num)

    # 2-获取模态质量
    modal_mass_list, v_eig_vals, v_eig_num_list = cable_stayed_bridge_modal_mass(eig_vals, get_mode_num)
    
    # 3-获取阻尼比
    zeta_list = cable_stayed_bridge_damping_ratio(eig_vals, v_eig_vals, girder_type)

    # 4-保存桥梁图片
    pic_info_list = []
    pic_info_list = cable_stayed_bridge_pic_output(image_path, v_eig_vals, v_eig_num_list, eig_vals)  # 保存图片，输出图片内容信息

    # 5-保存skeleton的json格式文件
    analysis_moment, bridge_address = cable_stayed_bridge_skeleton_output(bridge_skeleton, bridge_ID, \
                                                                          bridge_name, skeleton_path)

    # 6-输出参数结果
    bridge_output_data = []
    bridge_output_data = cable_stayed_bridge_output(bridge_name, v_eig_vals, zeta_list, modal_mass_list)

    # 7-建立桥梁信息字典
    # 7-1-建立信息转换字典
    girder_type_dict = {1:'plate', 2:'other', 3:'other', 4:'other', 5:'box', 6:'truss'}
    girder_mat_dict = {1:'concrete', 2:'steel', 3:'composite'}
    tower_type_dict = {1:'I', 2:'Y', 3:'A', 4:'H'}
    # 7-2-信息字典建立
    bridge_info_dict = {
                            "unionId": bridge_ID,
                            "dataTime": analysis_moment,
                            "bridgeName": bridge_name,
                            "bridgeAddress": bridge_address,
                            "structuralForm": "cablestay",
                            "bridgeTypeDetail": "cablestay",
                            "spanArrangement": spans,
                            "mainSpanLength": max(spans),
                            "pierArrangement": None,
                            "pierHeight": None,
                            "bridgeWidth": width,
                            "numOfLanes": int((width-3)/3.5),
                            "isNonMotorizedLane": False,
                            "isPedestrianWalkway": True,
                            "constructionMaterial": girder_mat_dict[girder_mat],
                            "mainBeamType": girder_type_dict[girder_type],
                            "numOfPylon": int(len(spans)-1),
                            "pylonHeight": tower_h_1*(1+1/tower_h_ratio),
                            "cablePlaneCount": int(cable_plane_num),
                            "cableCountPerSet": int(cable_num),
                            "pylonShape": tower_type_dict[tower_type_cross],
                            "auxiliaryPierCount": int(auxi_col_num),
                            "bridgeEndAPosition": None,
                            "bridgeEndBPosition": None,
                            "skeleton": None,
                            "oscillationFrequency": None,
                            "dampingRatio": None,
                            "modalMass": None,
                            "bridgeMassMatrix": None,
                            "bridgeStiffnessMatrix": None,
                            "constructionYear": [int(bridge_year)],
                        }

    # 7-结果返回
    return pic_info_list, bridge_output_data, bridge_info_dict
